类加载过程

类的加载过程包括加载, 验证, 准备, 解析, 初始化五个阶段.

  1. 加载

    加载过程实现三个事:

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

      二进制的获取方法:

    4. 从ZIP包中获取, 这是JAR, EAR, WAR格式的基础.

    5. 从网络中获取, 如Applet.
    6. 运算时计算生成, 运用最多的就是动态代理技术.
    7. 由其他文件生成, 如JSP.
    8. 从数据库中读取.
  2. 验证

    确保Class文件的字节流中包含的信息符合虚拟机的要求, 并且不会危害虚拟机的安全.

    1. 文件格式验证: 验证字节流是否符合Class文件格式规范, 并能被虚拟机处理.
    2. 元数据验证: 对字节码进行语义分析, 确保符合Java规范要求.
    3. 字节码验证: 对数据流和控制流分析, 确保程序语义是合法的, 符合逻辑的.
    4. 符号引用验证: 对类自身以外(常量池中的各种符号引用)的信息进行校验.
  3. 准备

    准备阶段为类变量分配内存并设置初始值, 使用的是方法区的内存.

    注意的是, 初始值一般为0, 下面的value就被初始化为0而不是123.

    1
    public static int value = 123;

    如果类变量是常量, 那么会按照表达式赋值, 而不是赋值为0.

    1
    public static final int value = 123;
  4. 解析

    将常量池的符号引用替换为直接引用.

  5. 初始化

    初始化阶段执行类构造器()方法.

    在准备阶段, 类变量已经赋过一次初始值了, 而在初始化阶段, 根据程序制定的去初始化类变量和其他资源.

    ()有一下特点:

    1. 此方法由编译器自动收集类中所有类变量的赋值动作和静态语句块中的语句合并产生. 静态语句块只能访问到定义在它之前的类变量, 定义在它之后的只能赋值, 不能访问. 否则会提示”非法向前引进”.

    2. 此方法不需要显式调用父类构造器.

    3. 如果一个类中不包含类变量的赋值操作, 也不包含静态语句块, 那么编译器可以不为该类生成()方法.