一、类加载过程

类加载过程详解

二、类加载过程详解

1、加载LOADING

将类的Class文件读入到内存中去,并创建java.lang.Class对象,无论Java使用什么类,都会创建java.lang.Class对象。

类的加载由类加载器完成,类加载器通常由JVM提供,这些类加载器也是前面所有程序运行的基础,JVM提供的这些类加载器通常被称为系统类加载器。除此之外,开发者可以通过继承ClassLoader基类来创建自己的类加载器。

类加载器

类加载器加载二进制数据的方式:

  • 从本地文件系统加载class文件,这是前面绝大部分示例程序的类加载方式
  • 从JAR包加载class文件,JVM可以从JAR文件中直接加载该class文件
  • 通过网络加载class文件
  • 把一个Java源文件动态编译,并执行加载

类加载器通常无须等到“首次使用”该类时才加载该类,Java虚拟机规范允许系统预先加载某些类

2、链接Linking

当类被加载后,系统为之生成一个对应的Class对象,接着将会进入连接阶段,连接阶段负责把类的二进制数据合并到JRE中。

其中主要分成了3个步骤:

  • 验证:验证阶段用于校验被加载的类是否有正确的内部结构,并和其他类协调一致。其验证主要包含文件格式验证(主要验证字节流是否符合Class文件格式规范,并且能被当前的虚拟机加载处理)、元数据验证(对字节码描述信息进行语义分析,分析是否符合Java语言规范)、字节码验证(最重要!分析数据流和控制,确定语义是合法的、符合逻辑的,主要对元数据验证后的方法体验证,保证类方法在运行时不会出现危害)、符号引用验证(主要是针对符号引用转换为直接引用的时候,延申到第三个步骤)
  • 准备:为静态变量分配内存,并设置默认值
  • 解析:将类的二进制数据中的符号引用( 符号引用是以一组符号来描述所引用的目标,符号可以是任何的字面形式的字面量,只要不会出现冲突能够定位到就行 )替换成直接引用( 是指向目标的指针,偏移量或者能够直接定位的句柄 )。

3、初始化

初始化是为类的静态变量赋予正确的初始值

三、类加载时机

  • 创建类的实例,使用new关键字
  • 访问某个类或接口的静态变量,或者对静态变量进行赋值
  • 调用类的静态方法
  • 反射
  • 初始化一个类的子类,会首先初始化子类的父类
  • JVM启动标明的启动类

 除此之外,下面几种情形需要特别指出:

     对于一个final类型的静态变量,如果该变量的值在编译时就可以确定下来,那么这个变量相当于“宏变量”。Java编译器会在编译时直接把这个变量出现的地方替换成它的值,因此即使程序使用该静态变量,也不会导致该类的初始化。反之,如果final类型的静态Field的值不能在编译时确定下来,则必须等到运行时才可以确定该变量的值,如果通过该类来访问它的静态变量,则会导致该类被初始化。

四、类加载器详解

1、根加载器(bootstrap class loader)用来加载Java核心类,是用C++编写,且没有父加载器,也不继承自java.lang.ClassLoader,主要负责加载由系统属性”sun.boot.class.path”指定的路径下的核心类库(jre\lib),出于安全考虑,根类加载器只加载java、javax、sun开头的类

测试说明:因为rt.jar是核心类库之一,而rt.jar里面的Object也是其中一员,所以获取Object的加载器就可以知道根加载器的一些属性

/**
 * @program: untitledDemo
 * @description: 根加载器
 * @author: crazy
 * @create: 2020-04-20 14:50
 **/
public class BootClassLoaderDemo {
    public static void main(String[] args) {
        ClassLoader objectLoader = Object.class.getClassLoader();
        System.out.println(objectLoader);
    }
}
运行结果

测试结果为null,是因为根加载器的特殊性决定的。

2、扩展类加载器(extensions class loader)负责加载JRE的扩展目录,lib/ext下jar中的类或者“java.ext.dirs”指定的目录下的类库,由Java语言实现,父类加载器是根类加载器(非继承关系)

import sun.net.spi.nameservice.dns.DNSNameService;

/**
* @program: untitledDemo
* @description: 扩展类加载器
* @author: crazy
* @create: 2020-04-20 14:50
**/
public class BootClassLoaderDemo {
public static void main(String[] args) {
ClassLoader extLoader = DNSNameService.class.getClassLoader();
System.out.println(extLoader);
System.out.println("___________________________________________");
ClassLoader extParentLoader = DNSNameService.class.getClassLoader().getParent();
System.out.println(extParentLoader);
}
}
运行结果

结果表明扩展类加载器的实际上是没有父类的

3、系统类加载器(app class loader)也称为应用类加载器,它的父类加载器是扩展类加载器,它负责从classpath环境变量或者系统属性java.class.path所指定的目录中加载类。它是用户自定义的类加载器的默认父加载器,一般情况下,该类加载器是程序中默认的类加载器,可以通过ClassLoader.getSystemClassLoader()直接获得

/**
 * @program: untitledDemo
 * @description: 系统类加载器
 * @author: crazy
 * @create: 2020-04-20 14:50
 **/
public class SystemClassLoaderDemo {
    public static void main(String[] args) {
        System.out.println(ClassLoader.getSystemClassLoader());
        System.out.println("___________________________________________");
        System.out.println(ClassLoader.getSystemClassLoader().getParent());
    }
}
运行结果

结果表明系统类加载器继承自扩展类加载器

4、上下文类加载器

分类: Java

0 条评论

发表评论

电子邮件地址不会被公开。