题目: 执行下面代码控制台输出什么?
public class Test1 extends Test12 { public Test1() { System.out.println("Test1类构造方法: c= " + c + " d= " + d); } { System.out.println("Test1 构造代码块"); } static { System.out.println("Test1静态代码块"); } int c = 300; static int d = 400; public static Test1 test1 = new Test1(); public static void main(String[] args) { new Test1(); } } class Test12 { public static Test12 test12 = new Test12(); { System.out.println("Test12 构造代码块"); } static { System.out.println("Test12 静态代码块"); } public Test12() { System.out.println("Test12类构造方法: a= " + a + " b= " + b); } int a = 100; static int b = 200; }
结果:
Test12 构造代码块 Test12类构造方法: a= 100 b= 0 Test12 静态代码块 Test1静态代码块 Test12 构造代码块 Test12类构造方法: a= 100 b= 200 Test1 构造代码块 Test1类构造方法: c= 300 d= 400 Test12 构造代码块 Test12类构造方法: a= 100 b= 200 Test1 构造代码块 Test1类构造方法: c= 300 d= 400
概念:
JVM不是一开始就把所有的类都加载进内存中,而是只有第一次遇到某个需要运行的类时才会加载,且只加载一次.
类什么时候才被初始化: 1. 创建类的实例,也就是new一个对象
2. 访问某个类或接口的静态变量,或者对该静态变量赋值
3. 调用类的静态方法
4. 反射(Class.forName(“com.test.Test1”))
5.初始化一个类的子类(会首先初始化子类的父类)
6. JVM启动时标明的启动类,即文件名和类名相同的那个类静态的代码块,类似于静态变量,不论类被实例化多少次,该区域代码只在第一次类加载初始化的时候执行一次.
构造代码块,在每次类被调用或者被实例化时就会被执行.
假设一个类没有父类,那么加载顺序为: (静态变量、静态代码块) –> (非静态变量、构造代码块) –> 构造器
如果有父类: (父类静态变量、父类静态代码块) -> (子类静态变量、子类静态代码块) -> (父类非静态变量、父类构造代码块) -> 父类构造器 -> (子类非静态变量、子类构造代码块) -> 子类构造器
* 注: ( )括起来的意思就是: 里面的按照 写代码的顺序按照从上到下的原则来初始化,谁在前面就先初始化谁 .
解析:
因为我们的主方法是在Test1中,所以当我们运行的时候就会先加载 Test1 类, 但是发现Test1 是有父类的Test12 ,那么就会先加载初始化其父类Test12
初始化 Test12 : 先加载 静态变量、静态代码块, 从上往下加载 .
先初始化 静态变量 test12 -> 按照 new 的要求,实例化一个对象,那么会先 初始化 构造代码块( 输出 :Test12 构造代码块 )、非静态变量 ( a = 100 被初始化了 ).
然后执行 Test12 的构造方法 : 输出 Test12类构造方法: a= 100 b= 0 , 因为静态属性 static int b 只是分配了空间,尚未被初始化赋值(200),因此,b 仍然存有缺省值 0。
静态属性 test12 ,初始化完成, 然后初始化静态代码块 ,输出 : Test12 静态代码块, 然后再初始化静态变量 b
从上往下初始化 子类静态变量、 输出: Test1静态代码块
当初始化 test1 的时候 , 又会看父类是否被初始化了 ,发现已经被初始化了,那就会调用Test12 的 构造代码块 和 构造方法 输出: Test12 构造代码块 , Test12类构造方法: a= 100 b= 200
再调用Test1的构造代码块和 构造方法,输出: Test1 构造代码块 , Test1类构造方法: c= 300 d= 400
最后,执行主方法内的 new Test1(); ,又会先调用Test12 的 构造代码块 和 构造方法 输出: Test12 构造代码块 , Test12类构造方法: a= 100 b= 200
再调用Test1的构造代码块和 构造方法,输出: Test1 构造代码块 , Test1类构造方法: c= 300 d= 400
参考文章:
还没有评论,来说两句吧...