天天看点

Java虚拟机如何加载Class文件

前面两篇博客,我详细的讲解下Java主动内存管理的一些情况,如果想要更深入的了解Java虚拟机的运行机制的话,我建议可以阅读下《深入理解Java虚拟机》这本书。而这篇博客主要记录的是Java虚拟机是如何把.class文件加载到内存,具体的加载过程是怎么样的呢?请看下面的详细讲解。 首先,必须得明白类加载机制大致原理:虚拟机把描述类的数据从CLASS文件加载到内存,并对数据进行校验,转换解析和初始化,最终形成可以被虚拟机直接使用的Java类型。 再次,必须得记住类加载的时机。类加载的生命周期:加载、验证、准备、解析、初始化、使用和卸载; 连接包括:验证、准备和解析; !

Java虚拟机如何加载Class文件

2)类初始化(立即)条件:加载、验证、准备已结束 A )遇到new, getstatic, putstatic, invokestatic指令时,如果累没有进行初始化,则需要先触发其初始化;对应的场景:使用new实例化对象;读取或设置类的静态字段;调用类的静态方法;   B)使用java.lang.reflect包的方法对类进行反射的时候;   C)当初始化一个类的时候,如果发现其父类没有初始化,需要先触发父类初始化;   D)当虚拟机启动时,要执行的主类,虚拟机会先初始化主类; 注意:(1)常量在编译期存入调用的常量池中,本质上没有直接引用到定义常量的类,因此不会触发定义常量的类的初始化。 下面再好好讲下加载类每一步,虚拟机做了哪些事: 一、加载   1)通过一个类的全限定名来获取定义此类的二进制字节流;   2)将这个字节流所代表的静态存储结构转化为方法区的运行时数据结构;   3)在内存中生成一个代表类的java.lang.Class对象,作为方法区类的各种数据的访问入口; 二、验证(连接的第一步) 1)目的:确保Class文件的字节流中包含的信息符合当前虚拟机的要求,并不会危害虚拟机自身的安全;   2)步骤:A)文件格式验证:验证字节流是否符合Class文件格式规范,并且能被当前版本的虚拟机处理; B)元数据验证:对字节码描述的信息进行语义分析,保证描述的信息符合java语言规范要求; eg:此类是否有父类;这个类的父类是否继承了不允许被继承的类;   C)字节码验证:最复杂;对类的方法体进行校验分析;   D)符合引用验证: **三、准备(赋值)**   1 )目的:为类变量分配内存并设置类变量初始值;类变量(被static修饰的变量)在方法区中分配;实例变量:在对象实例化时随对象一起分配到Java堆中; **四、解析**   1)目的:将常量池内的符号引用替换为直接引用的过程; **五、初始化(类加载最后一步)**:执行**类构造器<clinit>()方法**的过程 1)<clinit>()方法:由编译器自动收集类中的所有类变量的赋值动作和静态语块(static {})中的语句合并产生的;收集的顺序是由语句在源文件中出现的顺序; **静态语句块只能访问到定义在静态语句块之前的变量,定义在它之后的变量,在前面的静态语句块可以赋值,但是不能访问; ** 2)<clinit>()方法与类的构造函数(实例构造器<init>()方法)区别: **<clinit>()方法不需要显式调用父类构造器,VM会保证子类的<clinit>()方法执行之前,父类的<clinit>()方法已经执行完毕; ** 3)父类的<clinit>()方法先执行:**父类中的定义的静态语句块要优先于子类的变量赋值操作。 ** 4)**<clinit>()方法不是必需的**,如果类没有静态语句块,也没对变量的赋值操作,那么编译器不为类生成<clinit>()方法; 5)接口中不能使用静态语句块,但接口有变量的初始化赋值操作,因此接口和类都会生成<clinit>()方法;但执行接口的<clinit>()方法不需要先执行父接口<clinit>()方法; 6)VM保证一个类的<clinit>方法在多线程中被正确加锁、同步。 **常见的一些类加载器的分类(双亲委派模型): ** 1)虚拟机角度来看,两种不同的类加载器:   A)启动类加载器(Bootstrap ClassLoader):由C++实现,是VM的一部分;   B)所有其他的类加载器:由java实现,独立于VM外部;继承抽象类java.lang.ClassLoader; 2)程序员角度来看,可分为三种不同的类加载器:   A)启动类加载器(Bootstrap ClassLoader):负责将<JAVA_HOME>\lib目录中的,或被Xbootclasspath 参数所指定的路径中,并且是虚拟机识别的类库加载到内存中;无法被Java程序直接引用;在需要使用自 己加载器时,需要把启动类加载器赋null;   B)扩展类加载器(Extension ClassLoader):负责加载<JAVA_HOME>\lib\ext目录中的,或被java.ext.dirs系统变量所指定的路径中的所有类库;可直接使用扩展类加载器;   C)应用程序类加载器(Application ClassLoader):此加载器时ClassLoader中的getSystemClassLoader()方法的返回值,系统类加载器;负责加载用户路径(ClassPath)上所指定的类库;可直接使用此类加载器;程序默认的类加载器;