虚拟机类加载机制

2019-08-19  本文已影响0人  fomin

很多人觉得会写Java代码就行,Java底层怎么运行的不需要知道,但其实并不是这样,随着经验的积累,你需要了解越来越多的底层原理。我们先来看看下面的代码,看看class是怎样加载的。

public class BaseClass {
    static {
        System.out.println("BaseClass Init");
    }

    public static final String value = "BaseClass";
}

public class SubClass extends BaseClass {
    static {
        System.out.println("SubClass Init");
    }
}

public static void main(String[] args) {
    System.out.println(SubClass.value);
}

定义了一个父类BaseClass和子类SubClass,执行main方法会输出父类的“BaseClass Init”,而不是子类的,对于静态字段,,子类调用父类的静态字段吗,只会触发父类的初始化,而不会出发子类的初始化,为什么呢?下面我们来看下类的生命周期:
类从被加载到JVM内存中开始,到卸载出内存为止,它经历过了7个过程,包含加载(Loading)、验证(Verification)、准备(Preparation)、解析(Resolution)、初始化(Initialization)、使用(Using)和卸载(Unloading),其中验证、准备和解析称为连接。如图:


图片

图中可以看到解析和初始化有个双向箭头标注,这是因为支持Java的运行时绑定(动态绑定/晚期绑定)可以初始化开始后在执行解析,其它加载、验证、准备、初始化和卸载的顺序是确定的。对于初始化阶段,JVM规范严格规定了只有5中情况立即对类进行“初始化”(而加载、验证、准备自然需要在此之前开始):

加载阶段完成后,虚拟机外部的二进制字节流就按照虚拟机所需的格式存储在方法区之中,而且在Java堆中也创建一个java.lang.Class类的对象,作为程序访问方法区中这些类型数据的外部接口。

| 数据类型 | 默认值 | 数据类型 | 默认值 |
|:----:|:----:|:----:|:----:|:----:|:----:|:----:|:----:|
| int | 0 | long | 0L |
| short | (short)0 | char | ‘\u0000’ |
| byte | (byte)0 | boolean | false |
| float | 0.0f | double | 0.0d |
| reference | null | | |

总结

类加载过程中主要是将Class文件(准确地讲,应该是类的二进制字节流)加载到虚拟机内存中,真正执行字节码的操作,在加载完成后才真正开始。整个类加载过程中,除了在加载阶段可以自定义类加载器参与之外,其余所有的动作完全由虚拟机主导和控制。

上一篇 下一篇

猜你喜欢

热点阅读