对类的加载与实例化的学习,这一块的学习比较抽象,我们可以把抽象化的概念变得具体化,结合具体代码来帮助理解,把抽象的概念变为形象的概念,融入到自己的思想里。
一.将静态变量a和实例变量b写在构造方法之后。
main方法无论任何类当中,都会优先加载该类,当加载该类后,才会执行main方法中的语句。
public class Test {
private static Test test= new Test();
private Test() {
System.out.println(a);
System.out.println(b);
}
private int b = 3;
private static int a = 10;
public static void main(String[] args) {
}
}
这段代码的输出结果为0和3,证明输出a的值为0,b的值为3。
代码解析: 图中代码表示Test类进行加载,jvm进行语法检查无误后,遵循从上到下静态优先原则,首先会建立一个Test类的对象,此时需要调用构造方法Test(),之后又声明静态int类型的a值10,最后加载非静态int类型的b的值为3。我们将构造方法Test()中加入了输出a和b,因此在加载类时,会得到两个int类型的结果。
有的人可能会有疑问,图上代码按照顺序进行的话,那么将会报错,a和b并没有在调用构造方法T之前进行,但是为什么没有进行报错呢?
加载过程可以这样理解:对于我们口中所说的加载是进行从上到下静态优先的原则进行变量的声明与赋值,以及方法的内容加载。我们可以这样认为,在jvm进行语法检查后,才会进行我们所说的这个加载。
为什么b输出的值为3,而a输出的值是0而不是10呢,static是否影响结果呢?我们接着进行验证。
通过验证发现将声明变量a中的static去掉,那么输出结果变为a的值为10,证明是否为静态变量是影响结果的,然后此段代码在加载构造方法时,还没有加载到实例变量b和静态变量a,此时实例变量b的值为3,而静态变量a的值为int类型的默认值0。
二.将静态变量a放在构造方法调用之前。
public class Test {
private static int a = 10;
private static Test test= new Test();
private Test() {
System.out.println(a);
System.out.println(b);
}
private int b = 3;
public static void main(String[] args) {
}
}
此时控制台输出的值为10和3。
分析:此段代码在加载构造方法前,已经加载了静态变量a,但是还没有加载到实例变量b,此时输出a的值却为10,再结合第一段代码块,我们可以发现,静态变量必须要加载到,才可以输出它的值,当没有加载到时,构造方法中输出的这个静态变量a的值就为int类型的默认值0,证明静态变量依赖类的加载。
输出b却能得到b的值为3,之后我们将实例变量b放在任何位置,发现构造方法中输出的b的值永远都是3,证明实例变量并不依赖类的加载,java本身是面向对象的思想,执行任何操作,基本上都需要建立对象,我们可以认为实例变量本身也要依赖实例化对象后成为实例变量,那么输出实例变量b的值,无论b在那个位置都可以正常输出b的值,我们可以说实例变量可算对象的属性,当类要加载时,这个类的对象已经生成,实例变量b相当于其属性,在此对象的空间中,实例变量b是它的成员,无论放在哪个位置都可以随时被调用。
结论:证明了静态变量依赖类的加载,实例变量依赖对象,静态变量需要类加载到它时,它的值才会出来,否则它的值便是默认值,而实例变量是在本类中需要用到时,jvm可直接加载。
三.再main方法中进行实例化对象。
public class Test {
private static Test test= new Test();
private Test() {
System.out.println(a);
System.out.println(b);
}
private int b = 3;
private static int a = 10;
public static void main(String[] args) {
new Test();
}
可以得到控制台结果是0 3 10 3。
结论:主方法中实例化对象时,类已经加载完成。在类加载过程中,执行构造方法时,输出的a和b分别为0和3,但是类完全加载完成时,a和b已经被赋值为10和3了,刚才得到的结论静态变量依赖类的加载,此时已经加载完成,那么静态变量已经被赋值,此时输出a的值已经是10而不是默认值0。
我们通过以上验证,可以发现确实是静态变量依赖类加载,实例变量依赖对象,这个我们可以直接拿来用,这个原理支撑着java中很多东西,我们后续遇到相关问题,可以直接想一下这个原理。