虚拟机之类的加载机制

本贴最后更新于 1926 天前,其中的信息可能已经沧海桑田

类的生命周期

加载,验证,准备,解析,初始化,使用,卸载
解析和初始化的相对顺序不固定,解析可以在初始化之后,叫做动态解析或者动态绑定,对应继承或者接口的运行时。

虚拟机规范种的 5 种必须初始化的情况

  1. 遇到 new、getstatic、putstatic 或 invokestatic 这 4 条字节码指令时,如果类没有进行过初始化,则需要先触发其初始化。new 就是 new,getstatic、putstatic 是操作静态成员,invokestatic 是调用静态方法
  2. 对类反射调用
  3. 当初始化一个类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
  4. 当虚拟机启动时,用户需要指定一个要执行的主类(包含 main()方法的那个类),虚拟机会先初始化这个主类。
  5. 使用 JDK1.7 的动态语言支持时,比如 Groovy,如果一个 java.lang.invoke.MethodHandle 实例最后的解析结果 REF_getStatic、REF_putStatic、REF」nvokeStatic 的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。

题目

通过子类引用父类的静态字段,不会导致子类初始化

public static class Parent
{
    static {
        System.out.println("parent init");
    }
    public static int v=100;
}

public static class Child extends Parent
{
    static {
        System.out.println("child init");
    }

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

输出如下,在-XX:+TraceClassLoading 模式下,子类和父类都被加载了,但是只有父类被初始化了。

[Loaded class_loader_demo.ClassLoader1$Parent from file:/F:/Github/Demo/jvm/out/production/jvm/]
[Loaded class_loader_demo.ClassLoader1$Child from file:/F:/Github/Demo/jvm/out/production/jvm/]
parent init
100

会加载,但不会初始化

public static class Parent
{
    static {
        System.out.println("parent init");
    }
}
public static void main(String[] args) {
    Parent[] parents = new Parent[10];
}
public static class FinalClass
{
    public static final String constStr="FINAL";
    static {
        System.out.println("init");
    }
}

public static class UseFinalField
{
    public static void main(String[] args) {
        System.out.println(FinalClass.constStr);
    }
}

结果如下,常量被放到常量池里了

FINAL

继承下初始化的顺序

在定义成员的时候赋值语句是在 cinit 的最前面执行

  1. parent 的定义赋值
  2. parent cinit
  3. parent 构造函数
  4. child 的定义赋值
  5. child cinit
  6. child 构造函数

接口和类初始化的区别

当一个类在初始化时,要求具父类全部都巳经初始化过了,但是一个接口在初始化时,并不要求其父接口全部都完成了初始化,只冇在真正使用到父接门的时候(如引用接口屮定义的常量)才会初始化。

类加载器分类

  1. bootstrap classloader C 编写,加载 java 核心类,包括 ext 和 appclassloader,java 中没有对应的,打印 String.getClassLoader 会是 null
  2. extclassloader java 编写,加载/lib/ext 中的类
  3. appclassloader 加载 classpath 变量中的类,通常自定义的类就是由它加载
  4. 自定义类加载器

双亲委派模型

看这个词我以为自定义类加载器要有爹又有妈呢,其实就是一个职责链模式。

loadclass()和 forname()的区别

loaderClass 默认构造函数调用的是 resolve-false,不会类进行解析,因为不会初始化
forName 第二个参数 initialize 为 true,会初始化。

双亲委派工作机制

自底向顶检查,自顶向底加载。

根据双亲委派模式,在加载类文件时,子加载器首先会将加载请求委托给它的父加载器。
父加载器会检测自己是否已经加载过该类,如果己加载则加载过程结束;如果未加载则请求继
续向上传递,直到 BootstrapClassLoader。如果在请求向上委托的过程中,始终未检测到该类己
加载,则从 Boots 位叩 ClassLoader 开始尝试从其对应路径中加载该类文件,如果加载失败则由
子加载器继续尝试加载,直至发起加载请求的子加载器位为止。

双亲委派模式可以保证两点:一是子加载器可以使用父加载器己加载的类,而父加载器无
法使用子加载器己加载的类:二是父加载器己加载过的类无法被子加载器再次加载。这样就可
以保证 NM 的安全性和稳定性。

  • B3log

    B3log 是一个开源组织,名字来源于“Bulletin Board Blog”缩写,目标是将独立博客与论坛结合,形成一种新的网络社区体验,详细请看 B3log 构思。目前 B3log 已经开源了多款产品:SymSoloVditor思源笔记

    1090 引用 • 3467 回帖 • 297 关注
  • JVM

    JVM(Java Virtual Machine)Java 虚拟机是一个微型操作系统,有自己的硬件构架体系,还有相应的指令系统。能够识别 Java 独特的 .class 文件(字节码),能够将这些文件中的信息读取出来,使得 Java 程序只需要生成 Java 虚拟机上的字节码后就能在不同操作系统平台上进行运行。

    180 引用 • 120 回帖 • 3 关注

相关帖子

欢迎来到这里!

我们正在构建一个小众社区,大家在这里相互信任,以平等 • 自由 • 奔放的价值观进行分享交流。最终,希望大家能够找到与自己志同道合的伙伴,共同成长。

注册 关于
请输入回帖内容 ...