类的加载、连接、初始化
类的生命周期
类的加载、连接、初始化
在Java代码中,类型的加载、连接与初始化过程都是在程序运行期间完成的,提供了更大的灵活性,增加了更多的可能性。
加载:查找并加载类的二进制数据
连接:
验证:确保加载的类的正确性
准备:为类的静态变量分配内存,并将其初始化为默认值
解析:将Java中的符号应用转化为直接引用
初始化:为类的静态变量赋予正确的初始值
类加载
类加载器ClassLoader将java的.class文件中的二进制数据读入到内存中,将其放在运行时数据区的方法区中加载后,虚拟机在堆区创建一个与该类对应java.lang.Class对象,不管类的对象有多少个,与此类对应的Class对象只有一个,Class对象用来封装类在方法区内的数据结构,所以类里面的内容都可以通过Class对象获取。Class对象是反射的入口。类的加载并不是你首次使用的时候去加载,而是预料到某个类要被使用的时候预先加载它,加载过程中不会报错,只有在程序首次主动使用时,才会报错。
类主动使用
类的主动使用,将造成类的初始化,主动使用主要包括以下七类,其余使用均为被动使用:
1、new
2、调用或者设置静态变量
3、调用静态方法
4、有main方法的类
5、初始化子类时,先初始化父类
6、反射
7、JDK1.7开始提供的动态语言支持,java.lang.invoke.MethodHandle实例的解析结果,REF_getStatic,REF_putStatic,REF_invokeStatic句柄对应的类没有初始化则初始化。
注意:
1、对于静态字段来说,只有直接定义了该字段的类才会被初始化,当一个类在初始化时,要求其父类都已经初始化完毕。
2、常量在编译阶段会存入到调用这个常量的方法所在的类的常量池中,本质上调用类并没有直接引用到定义常量的类,不会造成初始化
3、当常量值并非在编译期间可以确定的,那么其值就不会被放到调用类的常量池中,这是会导致主动使用,造成初始化
4、对于数组实例来说,其类型是由JVM运行期动态生成的,其父类型就是Object,不会造成数组元素类初始化
5、当接口在初始化时,并不要求父接口都完成初始化;只有真正使用到父接口时,才会初始化
package com.jvm; /** * -XX:+TraceClassLoading 监听加载了哪些类, * TraceClassLoading前的+号表示开启某个功能;-号表示关闭某个功能 * -XX:<option>=<option> 表示为某个参数赋值 */ public class Test1 { static { System.out.println("main static block"); } public static void main(String[] args) throws Exception { //new,造成类初始化 new newTest(); System.out.println("===================="); //反射造成类初始化 Class cls = Class.forName("com.jvm.ReflectTest"); System.out.println("===================="); //直接调用父类静态变量不会初始化子类 System.out.println(Child1.str); System.out.println("===================="); //调用子类的静态变量,将先初始化父类(接口除外),然后初始化自己 System.out.println(Child2.str2); System.out.println("===================="); //调用确定初始值的常量,不是主动使用,不会造成初始化 System.out.println(Child3.str2); System.out.println("===================="); //调用不确定初始值的常量,会造成初始化 System.out.println(Child4.str2); System.out.println("===================="); //接口不会被初始化 System.out.println(Child5.str); System.out.println("=========================="); //初始化将按照静态变量顺序执行 System.out.println(Singleton.a); System.out.println(Singleton.b); } } class newTest{ static { System.out.println("newTest static block"); } } class ReflectTest{ static { System.out.println("ReflectTest static block"); } } class Parent1{ public static String str = "parent"; static { System.out.println("parent1 static block"); } } class Child1 extends Parent1{ public static String str2 = "child"; static { System.out.println("child1 static block"); } } class Parent2{ public static String str = "parent"; static { System.out.println("parent2 static block"); } } class Child2 extends Parent2{ public static String str2 = "child"; static { System.out.println("child2 static block"); } } class Parent3{ public static String str = "parent"; static { System.out.println("parent3 static block"); } } class Child3 extends Parent3{ public static final String str2 = "child"; static { System.out.println("child3 static block"); } } class Parent4{ public static String str = "parent"; static { System.out.println("parent4 static block"); } } class Child4 extends Parent4{ public static final double str2 = Math.random(); static { System.out.println("Child4 static block"); } } interface Parent5{ public static Thread thread = new Thread(){ { System.out.println("haha"); } }; } class Child5 implements Parent5{ public static String str = "parent"; static { System.out.println("Child5 static block"); } } class Singleton{ public static int a ; private static Singleton instentce = new Singleton(); public static int b = 0; private Singleton() { a++; b++; } public static Singleton getInstentce(){ return instentce; } }
执行main得到如下结果:
main static block
newTest static block
====================
ReflectTest static block
====================
parent1 static block
parent
====================
parent2 static block
child2 static block
child
====================
child
====================
parent4 static block
Child4 static block
0.17572662368886327
====================
Child5 static block
parent
==========================
1
0