二、类加载器与类初始化深度剖析
Demo01:
编写代码如下:
package com.zuoyan.classloader; class FinalTest{ public static final int x = 3; static { System.out.println("FinalTest static block!"); } } public class MyTest01 { public static void main(String[] args) { System.out.println(FinalTest.x); } }
代码执行结果:
3
Demo02:
然后将FinalTest 类中的 public static final x = 3 中的final 去掉 改成 public satic in x = 3
package com.zuoyan.classloader; class FinalTest{ public static int x = 3; static { System.out.println("FinalTest static block!"); } } public class MyTest01 { public static void main(String[] args) { System.out.println(FinalTest.x); } }
执行结果如下:
FinalTest static block!
3
Demo03:
然后再将 FinalTest 中的成员变量 public static final int x = 3 ,改成 public static final int x = new Random().nextInt(3);
package com.zuoyan.classloader; import java.util.Random; class FinalTest{ public static final int x = new Random().nextInt(3); static { System.out.println("FinalTest static block!"); } } public class MyTest01 { public static void main(String[] args) { System.out.println(FinalTest.x); } }
代码执行结果如下:
FinalTest static block!
1
Demo01 的执行结果是 3 ,没有输出静态代码块中的内容,就代表静态代码块没有被执行,也就是说类没有被初始化,如果类被初始化了,静态代码块是一定会执行的。
原因是: 本身 x 是 一个编译期的常量,3 在编译之后就会放在MyTest01 的常量池中,所以编译完后,MyTest01 和 FinalTest之间就没有任何关系了,删除FinalTest.class 没有任何关系
Demo02 的执行结果的原因是 : x 不是一个成员变量,需要加载类,所需需要初始化类
Demo03 结果出现的原因是: x 是一个成员变量,但是他的数值实在运行期才能确定的,所以需要加载FinalTest类
Demo04:
代码如下,请判断代码的执行结果
package com.zuoyan.classloader; class Parent{ static int a = 3; static { System.out.println("Parent static block"); } } class Child extends Parent{ static int b = 4; static { System.out.println("Child static block"); } } public class MyTest02 { static { System.out.println("MyTest9 static block"); } public static void main(String[] args) { System.out.println(Child.b); } }
代码的执行结果如下:
MyTest9 static block
Parent static block
Child static block
4
出现这样结果的原因: 首先初始化 Main 方法所在类,然后这类调用了 Child类的成员变量,导致了Child类的初始化,一个类的初始化首先会初始化他的父类,然后初始化他的子类
可用通过运行时 添加JVM参数来查看类的加载
程序执行输出的结果:
Demo05:
package com.zuoyan.classloader; class Parent2{ static int a = 3; static { System.out.println("Parent2 static block"); } } class Child2 extends Parent2{ static int b = 4; static { System.out.println("Child 2 static block"); } } public class MyTest03 { static{ System.out.println("MyTest03 static block "); } public static void main(String[] args) { Parent2 parent; System.out.println("-----------------"); parent = new Parent2(); System.out.println("-----------------"); System.out.println(parent.a); System.out.println("-----------------"); System.out.println(Child2.b); } }
程序执行的结果:
MyTest03 static block
-----------------
Parent2 static block
-----------------
3
-----------------
Child 2 static block
4
Demo06:
package com.zuoyan.classloader; class Parent3{ static int a =3; static { System.out.println("Parent3 static block"); } static void doSomething(){ System.out.println("do something"); } } class Child3 extends Parent3{ static{ System.out.println("Child3 static block"); } } public class MyTest04 { public static void main(String[] args) { System.out.println(Child3.a); Child3.doSomething(); } }
程序执行出来的结果:
Parent3 static block 3 do something
注意: a 本身是定义在父类中,我虽然通过子类来访问父类的成员变量,但是在本质上,是对于父类的主动使用,换句话说,就是成员变量定义在哪就是对谁的主动使用 (谁拥有就是对谁的主动使用)。
package com.zuoyan.classloader; class CL{ static { System.out.println("Class CL"); } } public class MyTest05 { public static void main(String[] args) throws Exception { ClassLoader systemClassLoader = ClassLoader.getSystemClassLoader(); Class<?> clazz = systemClassLoader.loadClass("com.zuoyan.classloader.MyTest05"); System.out.println(clazz); System.out.println("----------------------"); clazz = Class.forName("com.zuoyan.classloader.CL"); System.out.println(clazz); } }
执行结果:
class com.zuoyan.classloader.MyTest05
----------------------
Class CL
class com.zuoyan.classloader.CL