trigger [ˈtrɪɡə(r)]
触发器; 引爆器; 触发; 开动; 起动;
delegate [ˈdelɪɡeɪts]
代表;授(权);委托;选派
initiate [ɪˈnɪʃieɪt , ɪˈnɪʃiət]
开始; 发起; 创始;
Core Case
start ---> bootstrap class loader ---> rt.jar ---> initial class ---> public class ---> void mian() ---> link other class or interface ---> …
The Run-Time Constant Pool
全局常量池、class常量池、
每一个虚拟机、只有一个全局常量池、存放的是字符串常量的引用值。
运行时常量池中的符号引用是从类或接口的二进制表示形式的结构派生的.
运行时常量池中的所有引用最初都是符号性的. 类在解析之后,将符号引用替换成直接引用,与全局常量池中的引用值保持一致.
运行时常量值从类或接口的二进制表示形式中的CONSTANT_Integer_info,CONSTANT_Float_info,CONSTANT_Long_info或CONSTANT_Double_info结构派生。
/**
*
* <1> 访问的 static final 静态常量、编译阶段可以确定其值时,不会去加载定义它的类或接口、
*
* <2> 访问的 static final 静态常量、编译阶段无法确定其值是,会去加载定义它的类或接口,也会加载其父类和父接口,
* 同时会链接初始化其父类,但不会链接和初始化其父接口。
*
*/
类的主动使用7种情况:
- [x] 创建类的实例
- [x] 访问类或接口的静态变量、给静态变量赋值、
该静态变量 ----编译期间不能确定值/运行时才能完成赋值
- [x] 调用类的静态方法
- [x] 反射 ---- Class.forName()
- [x] 初始化类的子类
- [x] 虚拟机启动时被标记为启动类的类
- [x] JDK1.7开始提供的动态语言支持
加载(Loading)是查找具有特定名称的类类型或接口类型的二进制表示形式并从该二进制表示形式中创建类或接口的过程。
链接(Linking )是获取类或接口并将其组合到Java虚拟机的运行时状态以便可以执行的过程。
类或接口的初始化包括执行类或接口的初始化方法<clinit>. 该名称<clinit>由编译器提供. 不能直接用Java编程语言编写的程序中使用它.
5.3. Creation and Loading
- [x] 类或接口C的创建由另一个类或接口D触发,该类或接口D通过对其运行时常量池引用C。
- [x] 也可以通过某些Java SE平台类库中的调用方法D(例如反射)来触发类或接口的创建。
- [x] 如果C不是数组类,则通过使用类加载器加载C的二进制表示形式(类文件格式)来创建它。
- [x] 数组类没有外部二进制表示形式。它们是由Java虚拟机而不是由类加载器创建的。
- [x] 定义加载器 defining loader
- [x] 初始加载器 initiating loader
- [x] ClassLoader
- [x] BootstrapClassLoader
- [x] ExtClassLoader
- [x] AppClassLoader
- [x] user-defined class loader
java.lang.Object
--- java.lang.ClassLoader
--- java.security.SecureClassLoader
--- java.net.URLClassLoader
--- sun.misc.Launcher$ExtClassLoader
--- sun.misc.Launcher$AppClassLoader
- [x] JDK 1.0.2版中仅提供了一个含有两个参数的类加载器版本,Oracle的Java虚拟机实现依靠它来链接已加载的类或接口。
- [x] 从JDK 1.1版开始,Oracle的Java虚拟机实现调用了类加载器的loadClass方法,加载类或接口。loadClass的参数是要加载的类或接口的名称
- [x] 从JDK 1.1版开始,Oracle的Java虚拟机还有一个loadClass方法的两个参数版本,其中第二个参数是一个布尔值,指示是否要链接该类或接口。
- [x] 从JDK 1.1版开始,Oracle的Java虚拟机实现直接Link链接类或接口,而无需依赖类加载器。
运行时-类或接口的确定:binary name 和 defining class loader
类或接口的运行时包package:package name 和 defining class loader
创建类或接口:
- [ ] 如果D是由引导类加载器定义的、那么用引导类加载器启动加载C
- [ ] 如果D是由用户自定义类加载器所定义的、那么就用用户自定义类加载器来启动加载C
- [ ] 如果是数组类、那么该数组类是有虚拟机创建的,创建过程中会用到D的定义类加载器
LinkageError、ClassNotFoundException、NoClassDefFoundError
如果虚拟机记录了L是类或接口C的启动加载器、则不需要为C创建加载器、
直接调用L的loadClass方法、方法返回值 Class<?>是创建的类或接口C、最后虚拟机记录L是C的初始加载器。
loadClass方法2种实现方式:
1. 创建字节数组、表示为C的ClassFile结构的字节、然后调用ClassLoader类的defineClass方法、
2. 类加载L可以将类或接口C的加载委托给其他类加载器L'、将参数N直接或间接传递给L'上的方法调用(通常是loadClass方法)来实现的
相同的名称、返回同一个Class对象、L1委托L2加载类或接口C、则L1和L2应该返回相同的Class对象
Loading Using the Bootstrap Class Loader
Loading Using a User-defined Class Loader
Creating Array Classes
获取当前类的ClassLoader
class.getClassLoader();
获取当前线程上下文的ClassLoader
Thread.currentThread().getContextClassLoader();
获取调用者的ClassLoader
DriverManager.getCallerClassLoader();
5.5. Initialization
在类的链接阶段、为类体中的字段赋予默认值
类的初始化阶段、为类体中的字段赋予初始值
类的初始化
- [ ] 指令new、getstatic、putstatic、invokestatic
- [ ] 第一次调用java.lang.invoke.MethodHandle实例
- [ ] 调用某些反射方法,如在Class或包java.lang.reflect
- [ ] 初始化类的子类时、类会初始化
- [ ] Java虚拟机启动时指定的初始类
每个类或接口C、有一个唯一的初始化锁 LC、从C到LC的映射是由Java虚拟机实现自行决定
LC 可以是C的Class对象、或者是与该Class对象关联的监视器
绑定是一种过程、对非java需要的支持、以便可以执行该功能.
虚拟机退出:System.exit(0)、Runtime.getRuntime().halt(status)
链接
链接类或接口包括验证和准备类或接口、它的直接父类、直接父接口、它的元素类型
解析这个类或接口中的符号引用时链接过程的可选部分
链接之前必须被成功加载过、初始化之前必须成功被验证及准备过
链接过程会涉及数据结构的内存分配、可能导致OutOfMemoryError异常
验证 verification
验证阶段、确保类或接口的二进制表示在结构上是正确的
验证过程、可能会导致某些额外的类或接口被记载进来、但不一定需要验证和准备
验证失败、VerifyError、LinkageError
准备 preparation
准备阶段、创建类或接口的静态字段、并赋予默认值、此阶段不执行任何字节码指令
初始化阶段、会有显式的初始化器初始化这些静态字段、所以准备阶段不进行初始化
解析 resolution
解阶段、根据运行时常量池里的符号引用来动态决定具体值的过程
以下指令符号引用执行常量池、执行需要对符号引用进行解析:
anewarray、checkcase、getfield、instanceof、nvokedynamic、
invokeinterface、invokespecial、invokestatic、invokevirtual
ldc、ldc_w、multianewarray、new、putfield、putstatic、
invokedynamic执行的解析结果取决于一个具体值-----绑定到该指令调用点的对象
类或接口D的运行时常量池符号引用的解析过程:
- [ ] 类或接口解析
- D的定义加载器被用来创建常量池中符号引用的类或接口C
- 查询失败、IllgalAccessError
- [ ] 字段解析
- 先尝试在类或接口C中查找字段、
- 再尝试在类或接口C的父类中查找字段
- 如果具有相同字段名称及描述符则查找成功、否则递归查找直接父接口
- 查询失败、NoSuchFieldError
- [ ] 普通方法解析
- 如果C是接口、解析抛出异常IncompatibleClassChangeError
- 否则、方法引用解析过程会检查C和它的父类中是否包含此方法
- 否则、方法查找会尝试从C的父接口中缺定位所引用的方法
- 查询失败、NoSuchMethodError
- [ ] 接口方法解析
- 如果C不是接口、抛出IncompatibleClassChangeError
- 否则、在接口C中查找签名相同的接口方法
- 否则、在Object类中查找签名相同的接口方法
- 否则、在接口C的具体超接口中查找签名相同的接口方法
- 否则、在接口C的人以超接口中查找签名相同的接口方法
- 否则、查询失败
- [ ] 方法类型、方法句柄解析
- [ ] 调用点限定符解析
解析过程中、任何情况下、对类或接口解析不成功先抛出异常、之后才抛出解析字段的异常或解析方法的异常
访问控制、方法覆盖