类加载过程

3 篇文章 0 订阅

1、什么是类加载

就是JVM将描述类的数据从class文件加载到内存,并对数据进行校验、解析、初始化,最终形成能被JVM直接使用的Java类型。

2、类加载的触发时机

  • new
  • 读取或设置一个类的非finla修饰的静态变量
  • 调用类的静态方法,初始化该静态方法所在的类
  • 访问静态字段的指令时,初始化该静态字段所在的类
  • 对类反射调用
  • 初始化子类(父类会被先初始化)
  • 如果一个接口定义了 default 方法,那么直接实现或者间接实现该接口的类的初始化,会触发该接口的初始化;
  • 虚拟机启动时,main()的类先初始化
  • 当初次调用 MethodHandle 实例时,初始化该 MethodHandle 指向的方法所在的类

3、类加载执行过程

在这里插入图片描述

3.1、加载

根据全类名找到对应的class,将class的二进制数据读入内存,放到运行时区域的方法区内。然后在堆中创建java.lang.Class对象,用来封装类在方法区的数据结构(构造方法、成员方法、成员变量)。

3.2、验证

检查加载的 class文件的正确性

  • 文件格式验证:验证字节流文件是否符合Class文件格式的规范,并且能被当前虚拟机正确的处理。
  • 元数据验证:是对字节码描述的信息进行语义分析,以保证其描述的信息符合Java语言的规范要求
  • 字节码验证:主要是进行数据流和控制流的分析,保证被校验类的方法在运行时不会危害虚拟机。
  • 符号引用验证:符号引用验证发生在虚拟机将符号引用转化为直接引用的时候,这个转化动作将在解析阶段中发生。

3.3、准备

给类中的静态变量分配内存空间(赋初始值,但final修饰的类变量将会赋值成真实的值。)
比如:public static int initData = 1;
准备阶段 initData值为0;初始化阶段才会赋值为1;

3.4、解析

虚拟机将常量池中的符号引用(一个标识)替换成直接引用(指向内存中的地址)的过程
符号引用:包括类和接口的全限定名,字段的名称和描述符,方法的名称和描述符,它和虚拟机的内存布局是没有关系的,引用的目标不一定已经加载到了内存中。
直接引用:是直接指向目标的指针、相对偏移量或是一个能间接定位到目标的句柄。直接引用是和虚拟机实现的内存布局相关的,同一个符号引用在不同的虚拟机示例上翻译出来的直接引用一般不会相同。如果有了直接引用,那引用的目标必定已经存在在内存中了。

3.5、初始化

对静态变量、静态代码块执行初始化工作(赋实际值)
比如:public static int initData = 1;
准备阶段 initData值为0;初始化阶段则赋值为1;

4、类加载器的分类和作用

在这里插入图片描述类加载器不是继承体系,是委派体系。

4.1、启动类加载器(Bootstrap ClassLoader)

用来加载Java的核心类库(JAVA_HOME/jre/lib/rt.jar、resource.jar或sun.boot.class.path路径下的内容),用于提供JVM自身需要的类

4.2、扩展类加载器(Extensions ClassLoader)

从java.ext.dirs系统属性所指定的目录中加载类库,或从JDK的安装目录的jre/lib/ext子目录(扩展目录)下加载类库。如果用户创建的JAR放在此目录下,也会自动由扩展类加载器加载。

4.3、应用类(系统)加载器(APP ClassLoader)

根据Java应用的类路径(CLASSPATH)来加载Java类。一般来说。Java应用的类都是由它来完成加载的。可以通过ClassLoader.getSystemClassLoader()来获取它。

4.4、自定义类加载器

有需要时,可以自定义类加载器,来定制类的加载方式。

5、双亲委派模型

5.1、什么是双亲委派模型

在这里插入图片描述MyClassLoader进行类加载的时候,会先委托父类加载器(APPClassLoader)进行类加载,父类判断是否加载过,为加载过则APP再委托父类Extensions进行类加载,以此类推,Extensions再委托父类Bootstrap进行类加载。然后从Bootstrap开始加载,若在Java的核心类库下加载失败,则会往下进行加载,若所有父类都加载失败,则MyClassLoader自己进行加载操作。

  • 遵守双亲委派模型,实现findClass()即可。

5.2、为什么要有双亲委派模型

  1. 可以避免重复加载,当父类加载器加载成功时,子加载器就无需再次加载了。
  2. 可以防止java核心API被随意篡改,因为永远都是优先父级加载。

5.3、双亲委派模型能被打破吗?

可以,因为双亲委派模型不是强制性的。重写loadClass()即可。

例1:
jdk1.2之前还没有引入双亲委派,类加载时就是执行loadClass(),所以直接重写loadClass()就打破了双亲委派模型。
为了向前兼容,jdk1.2之后添加了新方法 findClass()。jdk1.2之后已不再提倡用户再去覆盖loadClass()方法。

例2:
Tomcat的web容器类加载器也破坏了双亲委派。自定义的WebApplicationClassLoader除了核心类库外,都是优先加载自己路径下的Class,这样有利于隔离、安全、热部署。

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

李_杰

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值