文讲到一个.java文件是如何变成一个.class文件以及Class文件的组成,在Class文件中描述的各类信息,最终都需要加载到虚拟机中之后才能被运行和使用。那么一个.class文件是如何加载到虚拟机中使用的呢?它是通过类加载器通过类加载的过程实现的。一个类的加载过程分为加载、验证、准备、解析、初始化、使用、销毁,JVM通过类加载器实现完成加载这一步骤,类加载器又分为BootStrapClassLorder、ExtensionClassLoader、ApplicationClassLoader、自定义类加载器。
一、类加载
一个类型从被加载到虚拟机内存中开始,到卸载出内存为止,它的整个生命周期将会经历加载、验证、准备、解析、初始化、使用、卸载七个阶段,其中验证、准备、解析三个部分统称为连接。
需要注意的是加载、验证、准备、初始化和卸载这五个阶段的顺序是确定的,类型的加载过程必须按照这种顺序按部就班地开始,而解析阶段则不一定:它在某些情况下可以在初始化阶段之后再开始,这是为了支持Java语言的运行时绑定特性(也称为动态绑定或晚期绑定)。
何时会进行类加载
1、遇到new、getstatic、putstatic或invokestatic这四条字节码指令时,如果类型没有进行过初始化,则需要先触发其初始化阶段(而加载、验证、准备自然需要在此之前开始)
new:创建类实例 使用new关键字实例化对象的时候
getstatic、putstatic访问类的域和类实例域 读取或设置一个类型的静态字段
invokestatic 调用命名类中的静态方法
2、使用java.lang.reflect包的方法对类型进行反射调用的时候,如果类型没有进行过初始化,则需要先触发其初始化。
3、当初始化类的时候,如果发现其父类还没有进行过初始化,则需要先触发其父类的初始化。
4、当虚拟机启动时,用户需要指定一个要执行的主类(包含main()方法的那个类),虚拟机会先初始化这个主类。
... 等等
接口的加载过程与类加载过程稍有不同 编译器仍然会为接口生成“()”类构造器,用于初始化接口中所定义的成员变量 但是一个接口在初始化时,并不要求其父接口全部都完成了初始化,只有在真正使用到父接口的时候(如引用接口中定义的常量)才会初始化。
1.加载:
加载,是指查找字节流,并且据此创建类或者接口的过程。加载阶段既可以使用Java虚拟机里内置的引导类加载器来完成,也可以由用户自定义的类加载器去完成,开发人员通过定义自己的类加载器去控制字节流的获取方式(重写一个类加载器的findClass()或loadClass()方法),实现根据自己的想法来赋予应用程序获取运行代码的动态性。
但是对于数组类而言,情况就有所不同,数组类本身不通过类加载器创建,它是由Java虚拟机直接在内存中动态构造出来的,因为数组它并没有对应的字节流,由Java虚拟机直接生成的。
在加载阶段,Java虚拟机需要完成以下三件事情
1、通过一个类的全限定名来获取定义此类的二进制字节流。这里不一定是class文件 可以从ZIP压缩包、JAR、EAR、WAR等格式中读取,可以从网络中获取,也可以运行时获取,也就是动态代理技术。
2、将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构。
3、在内存中生成一个代表这个类的java.lang.Class对象,作为方法区这个类的各种数据的访问入口。
加载一个类的时候会去先加载其父类,而且会有懒加载的机制(就是用到的时候才去加载这个类)。
来自 “ ITPUB博客 ” ,链接:https://blog.itpub.net/31414317/viewspace-2782088/ ,如需转载,请注明出处,否则将追究法律责任。