类初始化的一道面试题
下面的代码counter1,counter2输出的结果是什么,把第10行放到12行后面,ounter1,counter2输出的结果是什么? 为什么?
1 public class Test { 2 public static void main(String[] args) { 3 System.out.println(Singleton.counter1); 4 System.out.println(Singleton.counter2); 5 } 6 7 } 8 9 class Singleton{ 10 private static Singleton singleton = new Singleton(); 11 public static int counter1; 12 public static int counter2=0; 13 private Singleton(){ 14 counter1++; 15 counter2++; 16 } 17 public static Singleton getInstance(){ 18 return singleton; 19 } 20 }
1. counter1=1,counter2=0
原因是类初始化的准备阶段,会为静态变量分配内存,并设置默认初始值,此时singleton=null,counter1=0,counter2=0;然后在初始化阶段,为静态变量赋初始值,这时从上往下初始化,先new Singleton(), counter1=1,counter2=1,然后11行counter1没变,counter2被重新赋值为0。
2. counter1=1,counter2=1
原因是代码顺序换了,new Singleton()在后面执行。
类的初始化时机:主动使用(六种)
– 创建类的实例
– 访问某个类或接口的静态变量,或者对该静态 变量赋值
– 调用类的静态方法
– 反射(如 Class.forName(“com.shengsiyuan.Test”) )
– 初始化一个类的子类 – Java虚拟机启动时被标明为启动类的类(Java Test)
除了上述六种情形,其他使用Java类的方 式都被看作是被动使用,不会导致类的初始化
其他情况一:只有当程序访问的静态变量或静态方法确 实在当前类或当前接口中定义时,才可以 认为是对类或接口的主动使用
1 public class Test { 2 public static void main(String[] args) { 3 System.out.println(Child.a); 4 } 5 } 6 7 class Parent { 8 static int a = 3; 9 static { 10 System.out.println("Parent static block"); 11 } 12 static void doSomething(){ 13 System.out.println("do something"); 14 } 15 } 16 class Child extends Parent{ 17 static { 18 System.out.println("Child static block"); 19 } 20 }
输出
Parent static block 3
子类的静态代码块没有被执行,说明子类没有被初始化。
其他情况二:调用ClassLoader类的loadClass方法加载 一个类,并不是对类的主动使用,不会导 致类的初始化。
1 public class Test { 2 public static void main(String[] args) throws ClassNotFoundException { 3 ClassLoader loader = ClassLoader.getSystemClassLoader(); 4 Class<?> clazz = loader.loadClass("com.test.CL"); 5 System.out.println("---------------"); 6 clazz = Class.forName("com.test.CL"); 7 } 8 } 9 10 class CL { 11 static { 12 System.out.println("Class CL"); 13 } 14 }
输出
---------------
Class CL
ClassLoader的loadClass不会对类进行初始化。