类加载
2020-11-26 23:51:51 0 举报
AI智能生成
类加载过程
作者其他创作
大纲/内容
加载
普通类加载
1.通过一个类的全限定名来获取定义此类的二进制流
1.从ZIP包,WAR包,JAR包等读取字节流
2.从网路中获取,如Applet
3.运行时计算生成,如动态代理技术
4.有其他文件生成,如 JSP文件生成Class 类
.....
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3.在内存中生成一个代表这个类的java.lang.Class 对象,作为方法区这个类各种数据的访问入口
数组类加载
数组类不是通过类加载器创建,是Java虚拟机直接创建
1.数组的组件类型不是引用类型,则递归采用普通类加载过程加载组件类型,且数组将被标识在加载该组件类型的类加载器的类名空间上
2.如果数组的组件类型不是引用类型(int[] 的数组组件类型是int), Java虚拟机将会把数组标记为与引导类加载器关联
3.数组类的可访问性与它的组件类型的可访问性一致,如果数组不是引用类型,则数组类的可访问性将默认为public,可被所有的类和接口访问到
加载完成后,虚拟机外部的二进制字节流将存在方法区中,然后在内存中实列化一个java.lang.Class类的对象,作为程序访问方法区中的类型数据的外部接口
验证
1.文件格式验证
1.是否以魔数0xCAFEBABE开头
2.主次版本号是否在当前虚拟机处理范围内
3.常量池中是否有不被支持的常量类型
4.指向常量的各种索引值中是否有指向不存在的常量或者不符合类型的常量
5.CONSTANT_Utf8_info型的常量中是否有不符合utf-8编码的数据
6..Class 文件的各个部分及文件本身是否有被删除的或者被附加的其他信息
基于二进制流的验证,只有通过此阶段的验证,字节流才允许进入Java虚拟机内存的方法区中进行存储, 后面的三个阶段的验证是基于方法区的存储结构上进行的,不会直接读取,操作字节流
元数据验证
对类的元数据信息进行语义校验,保证不存在与Java语言规范相悖的元数据信息
1.类是否有除了Object之外的父类
2.父类是否继承了不允许被继承的类
3.如果此类不是抽象类,是否实现了其父类或者接口中要求实现的所有方法
4.类中的字段,方法是否与父类的产生矛盾(覆盖父类的final 字段,或不符合规定的重载如方法参数都一致,但返回值类型不同)
字节码验证
通过数据流分析和控制流分析,确定程序语义是否合法,符合逻辑,校验方法体(Class 文件中的Code 属性)
1.操作数栈的数据类型与指令代码序列都能配合工作
2.任何跳转指令都不会跳到方法体以外的字节码指令上
3.方法体中的类型转换总是有效的
符号引用验证
发生在虚拟机将符号引用转为直接引用的时候,转化动作在解析时发生,是对类自身意外的各类信息进行匹配性校验, 异常:java.lang.IllegalAccessError, java.lang.NoSuchFieldError, java.lang.NoSuchMethodError
1.符号引用中通过字符串描述的全限定名是否可以找到对应的类
2.指定类中是否存在符合方法的字段描述符及简单名称所描述的方法和字段
3.符号引用中的类,字段,方法的可访问性(private,protected,public,<package>)是否可被当前类访问
准备
为类中的定义的静态变量分配内存并设置类变量初始值,只有静态变量,初始值是数据类型的各个0值,实例变量将会在对象实例化的时候随对象一起分配在堆中
如果类字段的字段表中存在ConstantValue属性(final修饰),类变量的初始值就是真正的值
解析
Java虚拟机将常量池内的符号引用替换为直接引用过程
1.类或接口的解析
2.字段解析
3.方法解析
4.接口方法解析
5.方法类型解析
6.方法句柄解析
7.调用点限定符解析
初始化
类初始化
主动引用
1.遇到 new, getstatic,putstatic,invokestatic, 四条指令时,若类未初始化,则先进行初始化(4条指令在Java中代表: new一个对象,读取或者设置类的静态字段[被final 修饰的在编译期已放入常量池],调用类的静态方法)
2.使用java.lang.reflect包的方法队类进行反射调用时, 若未初始化,先初始化
3.初始化一个子类时,父类若未初始化则先初始化
4.虚拟机启动时,用户需要指定一个主执行类(包含main方法的那个类),虚拟机会先初始化此类
5.使用jdk1.7动态语言时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果为REF_getStatic,REF_putStatic,REF_invokeStatic四种类型的方法句柄,且这个方法句柄对应的类未初始化,则先初始化
6.接口定义了jdk8 新加入的默认方法时(被default修饰的接口方法),如果有这个接口的实现类且发生初始化,要先初始化接口,在初始化实现类
被动引用
1.通过子类引用父类的静态字段,不会导致子类初始化
2.通过数组定义来引用类, 不会触发此类的初始化
3.final 修饰的常量在编译期会存入调用类的常量池中, 本质上没用引用到定义常量的类, 所以不会触发定义常量类的初始化
接口初始化
接口与类初始化,唯一区别在于: 类初始化时,其父类必须全部初始化完, 接口不一定,在初始化接口时,不要求其父类全部初始化, 只有在真正使用到其父类接口的时候才会初始化(父类接口中的定义的常量)
使用
卸载
0 条评论
下一页