Java虚拟机学习札记(4)-连接模型
Java虚拟机学习笔记(4)-连接模型
允许用户自行设计类加载器,从而可以定制的扩展应用,可以装载编译时不知道甚至不存在的类或接口,并动态链接他
本note研究转载和解析细节,并解释如何扩展。。。
涉及:连接模型、常量池解析、方发表和如何编写和使用类转载器
1. 动态连接和解析
VM转载类和接口,并动态的将其中的符号引用连接起来。。
在类被首次加载的时候,定义类的class文件中的引用符号常量池会被一起转载到“运行时常量池中
当程序用到之前会保证解析触发,根据引用找到实体,并将符号替换为实体引用的过程(已解析过的常量池入口第二次会直接使用不解析)
vm可以自行实现何时进行常量解析,但都应该给外界一个延迟解析的印象。(比如:第一次访问才抛出错误)
1.1 解析和动态扩展
动态扩展的方式:
1)java.lang.Class#forName()方法(注意三参数的形式可以设定是否初始化)
2)用户自定义的加载器的loadClass()方法
------------使用forName可以init,使用loadClass可以定制class来源,并提供安全性措施
当解析类型过程中遇到其他引用时,会使用相同的classloader来装载
1.2 类转载器于双亲委派模型
系统类加载器默认是双亲,但也可以通过在构造函数中传递其他转载器来显示指定双亲
在这过程中,要求去转载但返回了其他装载器结果的装载器叫初始类转载器,而实际装载的转载器叫定义装载器
1.3 常量池解析
在解析过程中出现的错误会被看作指向执行解析的常量池入口的引用的引用者抛出的。。。
1.4 解析CONSTANT_CLASS_INFO入口
指向类和接口的符号引用,可能被指令直接使用或被间接使用
-1 数组类解析
如果入口的name_index以左方括号开头的,如[I,他就是一个数组类
如果是以L开头的则是一个关于引用的数组类
对于引用类型数组,当前classloader会加载指定类型,并最终生成Class
对基本类型,会立即创建数组类,并确定纬数,然后也创建出Class
-2非数组和接口
1a -> 装载类型和超类
首先,检查装载器维护的类型列表,确定是否已经装载,当没有装载时,就把类型名传入当前装载器....装载器有两个主要的选择(自行处理或委派其他来处理[通过loadClass委派或通过ClassLoader#findSystemClass()委派启动加载器])
在找到后,loadClass能找到一个byte[],之后通过数组和权限名调用defineClass()即可
vm会检查二进制数据,确定是否是Object,不是则通过super_class域向上寻找超类并加载;而在从Object返回的路上则会检查就扣信息。
通过1a,vm保证了类和类的超接口、超类都被加载完毕!
1b -> 连接并初始化
会检查类型的访问权限,保证已装载到正确的命名空间中。。。
2a -> 校验类型(可能引起其他加载)
2b -> 准备类型
为类变量和某些数据结构(方发表)分配内存
2c -> 可选的步骤,解析类型
这里指的是类、接口中对其他类、接口的引用常量的解析,这是可选的,可以延迟到使用前解析
2d -> 初始化类型
类可以自顶向下的进行初始化,并可能会调用clinit方法
1.5 解析CONSTANT_Fieldref_info入口
会以 类->超接口->超类的顺序寻找
1.6 CONSTANT_Methodref_info
首先,确认解析的类型是类不是接口
然后以类->超类 ->超接口找
1.7 CONSTANT_InterfaceMethodref_info
首先确定是接口
之后依次在接口和超接口中找(可以验证权限,全public)
1.8 CONSTANT_String_info
vm会把用到的字符串对象的引用替换常量符号。。。
vm内部会维护一个被拘留的字符串列表。。。singletion
1.9 其他类型的入口
CONSTANT_Integer_info\CONSTANT_Long_info\CONSTANT_Float_info\CONSTANT_Double_info基本可以直接解析
CONSTANT_Utf8_info\CONSTANT_NameAndType_info不会被直接引用
1.10 装载约束
vm必须保证不通loader的装载一致性
1.11 编译时常量解析
被初始化为编译时常量的final变量引用,编译时被解析为常量值的本地拷贝
这样!1)可以用户switch中 2)条件编译!
1.12 直接引用
指向实列变量和实列方法的直接引用是偏移量
(实列变量就是从开始到变量位置的偏移,实列方法是方法表的偏移)
如果使用顺序排列的方法实现invokevirtual或invokeinterface...对接口速度不快,估计有其他方法
1.13 X_quick指令
如果过常量池入口被解析过,使用常量池的操作码会被_quick代替,当vm遇到_quick指令时,可以更快处理
1.14 使用1.2版本的用户自定义类装载器
classloader#loadClass()在给定类型的全名后,loadClass会找到class文件的byte[],然后传递byte[]到defineClass中,此时还可以加入保护域
使用1.2可以直接覆盖findClass()方法,不需要再先findLoadedClass,再向上委托...
允许用户自行设计类加载器,从而可以定制的扩展应用,可以装载编译时不知道甚至不存在的类或接口,并动态链接他
本note研究转载和解析细节,并解释如何扩展。。。
涉及:连接模型、常量池解析、方发表和如何编写和使用类转载器
1. 动态连接和解析
VM转载类和接口,并动态的将其中的符号引用连接起来。。
在类被首次加载的时候,定义类的class文件中的引用符号常量池会被一起转载到“运行时常量池中
当程序用到之前会保证解析触发,根据引用找到实体,并将符号替换为实体引用的过程(已解析过的常量池入口第二次会直接使用不解析)
vm可以自行实现何时进行常量解析,但都应该给外界一个延迟解析的印象。(比如:第一次访问才抛出错误)
1.1 解析和动态扩展
动态扩展的方式:
1)java.lang.Class#forName()方法(注意三参数的形式可以设定是否初始化)
2)用户自定义的加载器的loadClass()方法
------------使用forName可以init,使用loadClass可以定制class来源,并提供安全性措施
当解析类型过程中遇到其他引用时,会使用相同的classloader来装载
1.2 类转载器于双亲委派模型
系统类加载器默认是双亲,但也可以通过在构造函数中传递其他转载器来显示指定双亲
在这过程中,要求去转载但返回了其他装载器结果的装载器叫初始类转载器,而实际装载的转载器叫定义装载器
1.3 常量池解析
在解析过程中出现的错误会被看作指向执行解析的常量池入口的引用的引用者抛出的。。。
1.4 解析CONSTANT_CLASS_INFO入口
指向类和接口的符号引用,可能被指令直接使用或被间接使用
-1 数组类解析
如果入口的name_index以左方括号开头的,如[I,他就是一个数组类
如果是以L开头的则是一个关于引用的数组类
对于引用类型数组,当前classloader会加载指定类型,并最终生成Class
对基本类型,会立即创建数组类,并确定纬数,然后也创建出Class
-2非数组和接口
1a -> 装载类型和超类
首先,检查装载器维护的类型列表,确定是否已经装载,当没有装载时,就把类型名传入当前装载器....装载器有两个主要的选择(自行处理或委派其他来处理[通过loadClass委派或通过ClassLoader#findSystemClass()委派启动加载器])
在找到后,loadClass能找到一个byte[],之后通过数组和权限名调用defineClass()即可
vm会检查二进制数据,确定是否是Object,不是则通过super_class域向上寻找超类并加载;而在从Object返回的路上则会检查就扣信息。
通过1a,vm保证了类和类的超接口、超类都被加载完毕!
1b -> 连接并初始化
会检查类型的访问权限,保证已装载到正确的命名空间中。。。
2a -> 校验类型(可能引起其他加载)
2b -> 准备类型
为类变量和某些数据结构(方发表)分配内存
2c -> 可选的步骤,解析类型
这里指的是类、接口中对其他类、接口的引用常量的解析,这是可选的,可以延迟到使用前解析
2d -> 初始化类型
类可以自顶向下的进行初始化,并可能会调用clinit方法
1.5 解析CONSTANT_Fieldref_info入口
会以 类->超接口->超类的顺序寻找
1.6 CONSTANT_Methodref_info
首先,确认解析的类型是类不是接口
然后以类->超类 ->超接口找
1.7 CONSTANT_InterfaceMethodref_info
首先确定是接口
之后依次在接口和超接口中找(可以验证权限,全public)
1.8 CONSTANT_String_info
vm会把用到的字符串对象的引用替换常量符号。。。
vm内部会维护一个被拘留的字符串列表。。。singletion
1.9 其他类型的入口
CONSTANT_Integer_info\CONSTANT_Long_info\CONSTANT_Float_info\CONSTANT_Double_info基本可以直接解析
CONSTANT_Utf8_info\CONSTANT_NameAndType_info不会被直接引用
1.10 装载约束
vm必须保证不通loader的装载一致性
1.11 编译时常量解析
被初始化为编译时常量的final变量引用,编译时被解析为常量值的本地拷贝
这样!1)可以用户switch中 2)条件编译!
1.12 直接引用
指向实列变量和实列方法的直接引用是偏移量
(实列变量就是从开始到变量位置的偏移,实列方法是方法表的偏移)
如果使用顺序排列的方法实现invokevirtual或invokeinterface...对接口速度不快,估计有其他方法
1.13 X_quick指令
如果过常量池入口被解析过,使用常量池的操作码会被_quick代替,当vm遇到_quick指令时,可以更快处理
1.14 使用1.2版本的用户自定义类装载器
classloader#loadClass()在给定类型的全名后,loadClass会找到class文件的byte[],然后传递byte[]到defineClass中,此时还可以加入保护域
使用1.2可以直接覆盖findClass()方法,不需要再先findLoadedClass,再向上委托...