JVM基础(六):成员变量和静态变量/静态初始化和非静态初始化
目录
1、成员变量和静态变量区别
1.两个变量的生命周期不同
- 成员变量随着对象的创建而存在,随着对象的被回收而释放;
- 静态变量随着类的加载而存在,随着类的消失而消失;
2. 数据存储位置不同
- 成员变量数据存储在堆内存的对象中,所以也叫对象的特有数据;
- 静态变量数据存储在方法区的静态区,所以也叫对象的共享数据;
3.调用方式不同
- 成员变量只能被对象调用;
- 静态变量能被对象调用,还能被类名调用;
4.别名不同
- 成员变量也称为实例变量;
- 静态变量被称为类变量;
举个栗子:
我们在面试的时候经常都会出现这样的一道题
下边的代码输出顺序是什么?
public class Test extends Base{
static{
System.out.println("test static");
}
public Test(){
System.out.println("test constructor");
}
public static void main(String[] args) {
new Test();
}
}
class Base{
static{
System.out.println("base static");
}
public Base(){
System.out.println("base constructor");
}
}
输出结果为:
base static
test static
base constructor
test constructor
我们先来想一下这段代码具体的执行过程,在执行开始,先要寻找到main方法,因为main方法是程序的入口,但是在执行main方法之前,必须先加载Test类,而在加载Test类的时候发现Test类继承自Base类,因此会转去先加载Base类,在加载Base类的时候,发现有static块,便执行了static块。在Base类加载完成之后,便继续加载Test类,然后发现Test类中也有static块,便执行static块。在加载完所需的类之后,便开始执行main方法。在main方法中执行new Test()的时候会先调用父类的构造器,然后再调用自身的构造器。因此,便出现了上面的输出结果。
总结
对象基本上都是在jvm的堆区中创建,在创建对象之前,会触发类加载(加载、连接、初始化),当类初始化完成后,根据类信息在堆区中实例化类对象,初始化非静态变量、非静态代码以及默认构造方法,当对象使用完之后会在合适的时候被jvm垃圾收集器回收。
对象的生命周期只是类的生命周期中使用阶段的主动引用的一种情况(即实例化类对象)。而类的整个生命周期则要比对象的生命周期长的多。
2、静态初始化和非静态初始化
从某种程度上来看,初始化块是构造器的补充,初始化块总是在构造器之前执行。
初始化块是一段固定执行的代码,它不能接受任何参数。因此初始化块对同一个类的所有对象所进
行的初始化处理完全相同。
如果有一段初始化处理代码对所有的对象完全相同,且无需接受任何参数,就可以把这段初始化处理代码提取到初始化块中。通过把多个构造器中的相同代码提取到初始化块中定义,能更好地提高初始化代码的复用。静态初始化块是类相关的,系统将在类加载时执行
静态初始化块,而不是在创建对象时才执行,因此静态初始化块总是比非静态初始化块先执行。用
途:例如在JNI调用时,需要加载动态链接库,就可以在静态代码块中加载。
2、内存分配实例
public class JVMCase {
// 常量
public final static String MAN_SEX_TYPE = "man";
// 静态变量
public static String WOMAN_SEX_TYPE = "woman";
public static void main(String[] args) {
Student stu = new Student();
stu.setName("nick");
stu.setSexType(MAN_SEX_TYPE);
stu.setAge(20);
JVMCase jvmcase = new JVMCase();
// 调用静态方法
print(stu);
// 调用非静态方法
jvmcase.sayHello(stu);
}
// 常规静态方法
public static void print(Student stu) {
System.out.println("name: " + stu.getName() + "; sex:" + stu.getSexType() + "; age:" + stu.getAge());
}
// 非静态方法
public void sayHello(Student stu) {
System.out.println(stu.getName() + "say: hello");
}
}
class Student{
String name;
String sexType;
int age;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public String getSexType() {
return sexType;
}
public void setSexType(String sexType) {
this.sexType = sexType;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}