JAVA虚拟机的类加载机制(一)

1. 类的生命周期和加载顺序

类从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期包括:加载、验证、准备、解析、初始化、使用、卸载七个阶段。其中验证、准备、解析3个阶段统称为连接。
类的生命周期

加载、验证、准备、初始化、卸载这5个阶段的顺序是确定的,但解析阶段不一定,它在某种情况下会在初始化之后再开始,这是为了支持java语言的动态语言绑定。
尽管加载顺序是确定的,但不意味着一个阶段执行完之后再执行下一个阶段,通常会在一个阶段执行的过程中调用、激活另一个阶段。

2. 类加载的时机

对于类加载过程中的第一阶段加载,java虚拟机规范中并没有进行强制约束,这点交给虚拟机的具体实现来自由把握。但是对于初始化阶段,虚拟机规范则规定有且只有5种情况必须立即对类进行初始化。当然加载,验证,准备会在初始化之前完成。

  • 遇到new关键字,获取或者引用静态变量

  • 使用反射获取对象

  • 当初始化一个类时,如果父类没有初始化,先对父类进行初始化。

  • 初始化程序入口main方法所在的主类。

  • 使用jdk1.7的动态语言支持,如果MethodHandle实例的解析结果是REF_getStatic,REF_putStatic,REF_InvokeStatic的方法句柄,并且这个类没有被初始化,则需要先触发其初始化。

以上五种情况被称为主动引用,另外的情况被称为被动引用(如下)。

1、通过其子类来调用父类的静态字段,只有触发父类的初始化,而不触发子类的初始化。
2、创建一个对象数组,不会对该类进行初始化,jvm会自动帮我们产生一个特殊的类,直接继承与object,创建动作由字节码指令newarray触发。该类可以调用的只有length属性和clone()方法。
3、通过类名调用被public final static 修饰的字段,不会对类进行初始化。因为被final修饰的字段,也就是常量。在进行类编译时会储存到类的常量池中。以后对本类中常量引用实际上调用的是类常量池中的引用。

3.类加载的过程

3.1 第一阶段 加载
在加载阶段,虚拟机要完成以下3个事情:
1)通过一个类的全限定名来获取定义此类的二进制字节流。
2)将这个二进制字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3)在内存中生产一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。(类对象存放在方法区中)

虚拟机没有指明二进制字节流从哪里获取,怎样获取,因此设计团队在加载阶段搭建了一个相当开放的,广阔的舞台。许多举足轻重的技术都是建立在这一基础之上。

1.从zip包中读取。
2.从网络中读取,这种场景最典型的应用就是Applet。
3.运行时计算生成,如动态代理技术。
4.由其他文件生成,典型场景就是JSP应用,由JPS文件生产Class类。
5.从数据库中读取。 …

值得一提的是,数组类本身不需要通过类加载器创建,但是他的元素类型是通过类加载器创建的。

猜你喜欢

转载自blog.csdn.net/weixin_42868206/article/details/82975840