标签:载器 动作 符号 启动 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