Android开发经验谈Android技术知识Android开发

类的加载机制

2018-07-23  本文已影响8人  金馆长说

类不被初始化的情况

  1. 对于静态字段,只有直接定义这个字段的类才会变初始化,子类引用父类的静态字段不会导致子类的初始化,只会初始化父类。
public class SuperClass {
    static {
        System.out.println("SuperClass init!");
    }
    public static int value = 123;


}

public class SubClass extends SuperClass {
    public static int aa=32;
    static {
        System.out.println("SubClass init!");
    }
}

  1. 数组的定义不会导致类的初始化
 SuperClass[] sca = new SuperClass[10];
  1. 使用静态常量不会导致类的初始化,因为常量在编译阶段就会存入调用类的常量池,本质上没有引用到定义类的常量,类在被编译成class之后,静态常量和类就没有关系了。

public class ConstClass {

    static {
        System.out.println("ConstClass init!");
    }

    public static final String HELLOWORLD = "hello world";

}


 public class Test {

    @org.junit.Test
    public void test() {
        System.out.println(ConstClass.HELLOWORLD);
    }

}  

类加载过程7阶段

加载、验证、准备、初始化和卸载这5个阶段的顺序是确定的,类的加载过程必须按照这个顺序按部就班的执行。

何时会执行加载的第一个过程?
这么五种情况是肯定会执行的

  1. 在遇到new 、读取或者设置一个类的静态字段(final除外,final在编译期间就放入了常量池)的时候,以及调用一个类的静态方法的时候。
  2. 使用反射调用的时候,如何类没有被初始化则会先触发其初始化。
  3. 类没有没有初始化的时候,如果其父类没有初始化。则需要先触发其父类的初始化。
  4. 执行一个main()方法
  5. 当使用JDK 1.7的动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。


    类的加载过程7个阶段

1. 加载

  1. 通过一个类名来获取到此类的二进制字节流
  2. 将字节流的静态存储结构转化为方法区运行时的数据结构
  3. 在内存中生成这个类的 Class对象,作为方法区的访问入口。


    JVM加载类图示过程
几种类加载器

2. 验证

  1. 文件格式验证
    这个步骤主要是检查字节流是否符合Class文件格式规范,是否以魔数0xCAFEBABE开头,版本号,常量问题。

下面是一个class得二进制字节码,cafe开头的就是魔数,它是JAVA之父自己定义的一个规则,CafeBabe代表咖啡宝贝,这个也符号Java的咖啡标志。


魔数
  1. 元数据验证
    这个阶段只要是对字节码进行语义分析,以保证字节码符合Java语义的规范,可能包含的检查有这个class是否有父类,是否集成了不允许继承的类比如final修饰的类,是否实现了父类要求实现的接口,字段是否产生了矛盾。

  2. 字节码验证
    这阶段是验证中最复杂的一步,主要是确定class的语义是否合法、符合逻辑,对类的方法体进行验证分析,保证类的方法不会对虚拟机安全造成危害。

  3. 符号引用验证
    这个阶段主要是检查class的一些访问修饰符是否符合规范,符号引用验证的目的是确保解析动作能正常执行。

3. 准备

准备阶段是正式为类变量分配内存并设置类初始值的阶段,分配static修饰的变量,这些变量所使用的内存都将在方法区中分配。

  public static int value = 123

value变量在被分配的时候,它的值不会是123而是默认的0。因为这个过程还未执行到Java代码,赋值为123的操作将在初始化阶段完成。

4. 解析

  1. 符号引用以一组符号来描述所引用的目标,它可以是新形势的字面量。
  2. 直接引用是指向目标的指针、相对偏移量或者一个能直接定位到目标的句柄。

解析类型主要有

  1. 类接口的解析
  2. 字段解析
  3. 类方法解析
  4. 接口方法解析

5. 初始化

类初始化是类加载过程中的最后一步,到了初始化阶段虚拟机才真正开始执行Java程序代码,准备阶段变量已经赋值过系统要求的初始值,而初始化阶段则回去初始化class的类变量和其他资源。

6. 使用

到了使用这一步就说明class已经正确的执行完了类加载的过程,class已经被加载到了虚拟机中,能被Java代码正确调用的过程。

7. 卸载

该类所有的实例都已经被GC,也就是JVM中不存在该Class的任何实例。

上一篇下一篇

猜你喜欢

热点阅读