类加载过程

2019-07-23  本文已影响0人  gczxbb

一、加载过程

类加载过程

加载,连接(验证,准备,解析),初始化,使用,卸载。

1,加载
class字节码文件描述类的各种信息。根据类全限定名,将二进制字节流加载到内存,可以是class文件外的其他渠道(如网络、动态生成),在堆生成一个代表类的Class对象,访问方法区类型信息数据的入口。
2,连接
验证,文件格式,元数据,字节码,符号引用。
准备,类变量分配内存,设置默认初始值0,(非final的static类型)。final类变量设置常量目标值。
解析,常量池符号引用转为直接引用。
3,初始化
类变量初始化语句和静态代码块,编译时,放在收集器,在<clinit>方法,类加载过程由JVM调用。优先初始化父类,仅允许一个线程对类初始化,没有静态变量和代码块时,可以没有<clinit>方法。

类信息
完整有效名,修饰符,类型直接接口的有序列表和父类,常量池,Field域信息,Method方法信息,静态变量static,classloader引用。

二、类初始化

触发条件

创建一个类的对象实例,new关键字、反射、序列化。
读取一个类或接口public静态变量,(final除外)。
调用一个类的静态方法。
使用java.lang.reflect包的方法对类反射调用。
初始化一个类的派生类时,先初始化该类。
jvm启动包含main方法的启动类。

public class Tea {
    public static int a  = 10 ;  
    public Tea(){
        System.out.println("构造方法代码");
    }
    static {              
        System.out.println("类初始化代码");
    }
    public static int b  = 100 ;    
    static {              
        System.out.println("类初始化代码2");
    }
}

Tea类,静态变量a和b赋值,静态代码块,反编译Tea结果。

反编译Tea类

编译器会自动搜集类变量的赋值动作与静态代码块语句,按照源文件出现的顺序,合并生成static{}方法。
外部访问Tea.a变量时,Tea类初始化,按照出现的顺序赋值和执行。如果Tea有父类,父类初始化在子类前执行。
Tea2类,继承Tea类。

public class Tea2 extends Tea{
    public static int c  = 10 ;  
    public static final int d  = 10 ; 

    public Tea2(){
        System.out.println("构造方法代码");
    }

    static {              
        System.out.println("类初始化代码3");
    }
}

1,外部访问Tea2.a变量,仅Tea类初始化,Tea2不会初始化,子类引用父类静态变量,仅父类初始化,子类不会初始化。
2,外部访问Tea2.c变量,Tea2类初始化,先初始化Tea类。
3,外部访问Tea2.d变量,Tea2类不会初始化,final常量在编译阶段存储在类常量池,不会导致该类初始化。
4,外部定义一个Tea2类型数组,Tea2类不会初始化。

public class Tea3 {
    public static int e  = 10 ;  
    public static int b = 12;
    public static Tea3 f  = new Tea3() ;
    
    public Tea3(){
        System.out.println("构造方法代码:a="+a+" b="+b);
    }

    static { 
        b+=1;
        System.out.println("类初始化代码");
    }
   
    public int a = 11;  
    public static Tea3 g  = new Tea3() ;
}

外部引用Tea3.e变量,导致Tea3类初始化,流程:
1,初始化e,b变量值,
2,Tea3实例f,a实例变量初始化11,构造方法,打印a=11,b=12,
3,初始化static{}代码,b值自增。
4,初始化Tea3实例g,a实例变量初始化11,构造方法,打印a=11,b=13。

因此,实例初始化不一定在类初始化结束才开始,类初始化时,遇到静态对象赋值,将会进行实例初始化。

将实例化嵌入到类初始化流程中,导致实例化发生在某些类变量初始化之前。初始化本质是赋值,创建对象后,按顺序如果某个static变量还未初始化值就是0。

三、总结

1,实例初始化不一定在类初始化结束后开始。

2,虚拟机保证类构造器方法的加锁和同步,在同一个类加载器,一个类型只会被初始化一次。

3,如果没有类变量或静态代码块,可以不产生类构造器。

4,子类引用父类静态变量,仅父类初始化,子类不会初始化。


任重而道远

上一篇 下一篇

猜你喜欢

热点阅读