JAVA的语言类型可以分为两大类:基本类型和引用类型,其中引用类型可以细分为四种:类、接口、数组类和泛型参数。泛型参数在编译的过程中会被擦除;数组类是由Java虚拟机直接生成的;而类和接口则有对应的字节流。常见的字节流是有Java编译器生成的.class文件,这些字节流会被加载到Java虚拟机中成为类或接口
类和接口被Java虚拟机加载的过程有三个步骤:加载、链接、初始化。
加载:
加载就是加载字节流,并且根据字节流创建类或接口的过程。加载字节流程的过程中,Java虚拟机需要借助类加载器来完成字节流的加载。
启动类加载器(boot class loader):启动类加载器是有C++实现的,没有对应的Java对象,因此在Java中只能使用null来指代。在Java9以前,启动类加载器负责加载最为基础、最为重要的类,比如放在JRE的lib目录下jar包中的类(以及由虚拟机参数-Xbootclasspath指定的类)。
Java中另外两个重要的类加载器是:扩展类加载器(Java9以后改为平台类加载器)和应用类加载器,他们都是由Java核心类库提供。
扩展类加载器:扩展类加载器的父类是启动类加载器,它负责加载相对次要但又通用的类。比如放在JRE的lib/ext目录下jar包中的类(以及由系统变量java.ext.dirs指定的类)。
应用类加载器:应用类加载器的父类加载器则是扩展类加载器,它负责加载应用程序路径下的类(应用程序路径值得是虚拟机参数-cp/-classpath、系统变量java.class.path或环境变量CLASSPATH所指定的路径)。默认情况下,应用程序中包含的类就是由应用类加载器加载。
除了启动类加载器,其它类加载器都是java.lang.ClassLoader的子类,有对应的java对象,这些加载器需要先有另一个加载器,加载到虚拟机中,才能执行类的加载。(比如说启动类加载器)
双亲委派模型:每当一个加载器接收到加载请求后,它都会将请求转发给父类加载器,在父类加载器没有找到所请求的类的情况下,该加载器才回去尝试加载。委派的好处就是避免了有些类被重复加载。
在Java虚拟机中,类的唯一性由类加载器实例和类的全名一同决定的。同一串字节流经过不同的类加载器加载也会的到不同的类。
链接:
链接是指将创建成的类合并到Java虚拟机中,使之能够执行的过程。链接又可以分为:验证、准备、解析三个阶段。
验证阶段的目的:保证被加载的类能够满足Java虚拟机的约束条件,通常而言Java编译器生成的类文件必然能够满足Java虚拟机的约束条件。
准备阶段的目的:为被加载类的静态字段分配内存,静态字段的初始化则会在稍后的初始化阶段进行。除了分配内存,部分Java虚拟机还会在这个阶段构造其它跟类层次相关的数据结构(比如用来实现虚方法的动态绑定的方法表)。
在class被加载到Java虚拟机之前,这个类我发知道其它类及其方法、字段、所对应的具体地址,甚至不知道不知道自己方法、字段的地址。因此每当要引用这些成员时,Java编译器会生成一个符号引用,在运行阶段,这个符号引用能够无歧义的精确地定位到具体的目标上。
解析阶段的目的:正是将这些符号引用解析成为实际引用。如果符号引用指向一个未被加载的类、或未被加载类的方法、字段时。将触发这个类的加载(但未必触发这个类的链接和初始化)。
Java虚拟机规范没有要求在链接过程中完成解析,它仅规定了:如果某些字节码使用了符号引用,那么在执行这些字节码之前,需要对这些符号引用的解析。
初始化:
在Java中如果要对一个静态字段初始化,可以直接在声明时对其赋值,也可以在静态代码块中对其赋值。如果直接赋值的静态字段被final修饰,并且它的类型是基本类型或者字符串时,那么该字段会被Java编译器标记为常量,它的初始化直接由Java虚拟机完成。除此之外的直接赋值操作,以及所有静态代码块中的代码,都是被Java编译器置于同一个方法中,并将该方法命名为<clinit>。
初始化的过程就是为这些标记为常量字段赋值,以及执行<clinit>方法的过程,Java虚拟机会通过加锁,来保证类的<clinit>方法只执行一次。
只有当初始化阶段完成后,类才正式成为可执行状态。
什么情况下会触发类的初始化:
1.当虚拟机启动时,初始化用户指定的主类。
2.当遇到新建目标类实例的new指令时,初始化new指令的目标类。
3.当遇到调用静态方法的指令时,初始化该静态方法所在的类。
4.当遇到调用静态字段的指令时,初始化该静态字段所在的类。
5.子类初始化会触发父类的初始化。
6.如果一个借口定义了default方法,那么直接实现或间接实现该接口的类初始化时,会触发该接口的初始化。
7.使用反射API对某个类进行反射调用时,会初始化这个类。
8.当初次调用 MethodHandle 实例时,初始化该 MethodHandle指向的方法所在的类。
注:该文章是本人学习郑雨迪老师的课程笔记。