虚拟机类加载机制

虚拟机类加载机制


1.把描述类的数据从Class文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型,这就是虚拟机的类加载机制。
java的类型加载和连接过程都是在程序运行期间完成的,java天生可以动态扩展的语言特性就是依赖运行期动态加载和动态连接实现的。


2.类的生命周期:加载,验证,准备,解析,初始化,使用,卸载。 (验证,准备,解析称为连接)

类加载时机:JAVA虚拟机在有且仅有的5种场景下会对类进行初始化。
1.遇到new、getstatic、setstatic或者invokestatic这4个字节码指令时,对应的java代码场景为:new一个关键字或者一个实例化对象时、读取或设置一个静态字段时(final修饰、已在编译期把结果放入常量池的除外)、调用一个类的静态方法时。
2.使用java.lang.reflect包的方法对类进行反射调用的时候,如果类没进行初始化,需要先调用其初始化方法进行初始化。
3.当初始化一个类时,如果其父类还未进行初始化,会先触发其父类的初始化。
4.当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的类),虚拟机会先初始化这个类。
5.当使用JDK 1.7等动态语言支持时,如果一个java.lang.invoke.MethodHandle实例最后的解析结果REF_getStatic、REF_putStatic、REF_invokeStatic的方法句柄,并且这个方法句柄所对应的类没有进行过初始化,则需要先触发其初始化。
这5种情况被称为是类的主动引用,注意,这里《虚拟机规范》中使用的限定词是"有且仅有",那么,除此之外的所有引用类都不会对类进行初始化,称为被动引用。静态内部类就属于被动引用的行列。


对于静态字段,只有直接定义这个字段的类才会被初始化
static final修饰的变量,其他类引用时,不会初始化定义这个变量的类,因为在其他类中的引用都转化为自己的常量池的引用
接口初始化时,不要求父接口也初始化,只有使用到父接口(引用父接口中定义的常量)时才会初始化

3.类加载的过程
加载,验证,准备,解析,初始化

加载:虚拟机需要完成3件事:
1.通过类的全限定名获取定义此类的二进制字节流
2.将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构
3.java堆中生成一个代表这个类的Class对象,作为方法区中数据的访问入口

验证:确保Class文件的字节流包含的信息符合当前虚拟机的要求,不会危害虚拟机自身安全
1.文件格式验证:经过这个阶段,字节流才会进入方法区存储。
是否以魔树开头
主次版本号是否在当前虚拟机处理范围内
常量池的常量是否有不被支持的常量类型等

2.元数据验证:保证不存在不符合java语言规范的元数据信息
 是否有父类
 父类是否继承了不允许被继承放入类(final修饰的)
 若不是抽象类,是否实现了父类或接口中要求实现的所有方法
 
3.字节码验证:对类的方法体进行校验
操作数栈中的类型和使用时的类型是否匹配
跳转指令是不水跳转到方法体以外的字节码指令

4.符号引用验证:发生在虚拟机将符号引用转化为直接引用的时候
符号引用通过字符串描述的全限定名是否能找到对应的类
指定类中是否存在符号方法的字段描述符及简单名称所描述的方法和字段

-Xverify:none参数来关闭大部分的类验证以缩短虚拟机类加载的时间

准备:为类变量(static)分配内存并设置初始值
static 的赋值:putstatic指令被编译后没存放在类构造器<clinit>方法中,在类初始化时才赋值为XX
static final :编译时生成ConstantValue属性,准备阶段直接赋值XX

解析:将常量池内的符号引用替换为直接引用的过程
符号引用:以一组符号来描述所引用的目标,可以使任何形式的字面量(文本字符串,或被声明为final的常量)
直接引用:直接指向目标的指针,相对偏移量,或句柄

初始化:执行类构造器<clinit>方法的过程
<clinit>方法由编译器收集类中所有类变量的赋值动作和静态语句块中语句合并产生,静态语句块中只能访问到定义在静态语句块之前的变量,
静态代码块之后的变量,在语句块中智能赋值 不能访问

类中若没有静态语句块,也没有对变量的赋值操作,则可以不生成<clinit>方法


4.类加载器:作用:通过一个类的全限定名获取此类的二进制字节流。


1.只有在两个类是由同一个类加载器加载的前提下 两个类才能相等。否则,即使是来源于同一个Class文件,类也不相等

2.双亲委派模型
启动类加载器:Bootstrap ClassLoader:将<JAVA_HOME>\lib目录中类库加载到虚拟机中。不能被java程序直接使用

扩展类加载器:Extension ClassLoader:lib\ext下的类库,开发者可直接使用

应用程序类加载器:Application ClassLoader:加载ClassPath上的类库。程序中默认的类加载器

3.破坏双亲委派原则:
基础类要调用回用户的代码:JNDI,JDBC:父类加载器请求子类加载器完成类加载
模块化热部署:用自定义的类加载机制实现



 

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值