标签:载器 动作 符号 启动 bootstra 分配 动态 支持 特殊
JVM 会在程序第一次主动引用类的时候,加载该类,被动引用时并不会引发类加载的操作。也就是说,JVM 并不是在一开始就把一个程序就所有的类都加载到内存中,而是到不得不用的时候才把它加载进来,而且只加载一次。那么什么是主动引用,什么是被动引用呢?
Array[] arr = new Array[10]; 不会触发 Array 类初始化;static final VAR 在编译阶段会存入调用类的常量池,通过 ClassName.VAR 引用不会触发 ClassName 初始化。也就是说,只有发生主动引用所列出的 5 种情况,一个类才会被加载到内存中,也就是说类的加载是 lazy-load 的,不到必要时刻是不会提前加载的,毕竟如果将程序运行中永远用不到的类加载进内存,会占用方法区中的内存,浪费系统资源。
ClassLoader#loadClass(className) 或 Class.forName(className)。Class.forName(className) 加载 class 的同时会初始化静态域,ClassLoader#loadClass(className) 不会初始化静态域;加载 --> 验证 --> 准备 --> 解析 --> 初始化 --> 使用 --> 卸载
|<------- 连接 ------->|
|<------------- 类加载 ---------------->|
类的生命周期一共有 7 个阶段,其中前五个阶段较为重要,统称为类加载,第 2 ~ 4 阶段统称为连接,加载和连接中的三个过程开始的顺序是固定的,但是执行过程中是可以交叉执行的。接下来,我们将对类加载的 5 个阶段进行一一讲解。
[L全类名 对象的初始化0xCAFEBABE-Xverify:none 关掉。public static int value = 123;
<client>() 方法中,<client>()方法会在初始化时执行,也就是说,value 变量只有在初始化后才等于 123。public static final int value = 123;
static final 赋值之后 value 就不能再修改了,所以在这里进行了赋值之后,之后不可能再出现赋值操作,所以可以直接在准备阶段就把 value 的值初始化好。<client>() 方法的过程。<client>() 方法
<client>() 方法中的语句顺序:
<init>() 的不同:
<client>() 方法;<client>() 方法执行前,父类的 <client>() 方法一定执行完毕。
<client>() 方法前不需要先执行父接口的 <client>() 方法(除非用到了父接口中定义的 public static final 变量);<client>() 方法,因为虚拟机要保证在同一个类加载器下,一个类只被加载一次。<client>() 方法。注:初始化时,才真正开始执行类中定义的 Java 代码。
instanceof 关键字equals()isInstance()isAssignableFrom()parent.loadClass(name, false)extends ClassLoader,然后重写 findClass() 方法而不是 loadClass() 方法,这样就不用重写 loadClass() 中的双亲委派机制了标签:载器 动作 符号 启动 bootstra 分配 动态 支持 特殊
原文地址:https://www.cnblogs.com/mengY/p/12254504.html