【教3妹学java】类加载的过程是什么样的?

2022-07-04  本文已影响0人  程序员小2

插: 前些天发现了一个巨牛的人工智能学习网站,通俗易懂,风趣幽默,忍不住分享一下给大家。点击跳转到网站。
坚持不懈,越努力越幸运,大家一起学习鸭~~~

3妹

2哥:"今天只有残留的躯壳,迎接光辉岁月"
3妹:"风雨中抱紧自由,一生经过彷徨的挣扎"
2哥:哟,3妹小小年纪也会唱beyond的歌啊?
3妹:这首歌这么火,我会唱有什么稀奇的
2哥:还以为你只会唱一些小女生喜欢的歌呢
3妹:2哥怎么想起来唱这首歌了哇
2哥:不是你说岁月是把杀猪刀,岁月对我很残忍嘛,我就追忆一下岁月。
3妹:哈哈哈哈,岁月虽然摧残了2哥的身体,可是也让2哥从中学了很多东西啊,比如2哥的java就比我强很多,快教教我啦。
2哥:那今天我们就学习一下java的类加载过程。

讲课

类加载器

类加载器是 Java 运行时环境(Java Runtime Environment)的一部分,负责动态加载 Java 类到 Java 虚拟机的内存空间中。类通常是按需加载,即第一次使用该类时才加载。 由于有了类加载器,Java 运行时系统不需要知道文件与文件系统。每个 Java 类必须由某个类加载器装入到内存。

类加载

类装载器除了要定位和导入二进制 class 文件外,还必须负责验证被导入类的正确性,为变量分配初始化内存,以及帮助解析符号引用。这些动作必须严格按一下顺序完成:

  1. 装载:查找并装载类型的二进制数据。
  2. 链接:执行验证、准备以及解析(可选) - -验证:确保被导入类型的正确性 -准备:为类变量分配内存,并将其初始化为默认值。
  1. 初始化:把类变量初始化为正确的初始值。

装载

类加载器分类

在Java虚拟机中存在多个类装载器,Java应用程序可以使用两种类装载器:

全盘负责双亲委托机制

在一个 JVM 系统中,至少有 3 种类加载器,那么这些类加载器如何配合工作?在 JVM 种类加载器通过 全盘负责双亲委托机制 来协调类加载器。

全盘负责双亲委托机制只是 Java 推荐的机制,并不是强制的机制。实现自己的类加载器时,如果想保持双亲委派模型,就应该重写 findClass(name) 方法;如果想破坏双亲委派模型,可以重写 loadClass(name) 方法。

装载入口

所有Java虚拟机实现必须在每个类或接口首次主动使用时初始化。以下六种情况符合主动使用的要求:

除以上六种情况,所有其他使用Java类型的方式都是被动的,它们不会导致Java类型的初始化。 当类是被动引用时,不会触发初始化:

1.通过子类去调用父类的静态变量,不会触发子类的初始化,只会触发包含这个静态变量的类初始化,例如执行这样的代码SubClass.fatherStaticValue只会触发FatherClass的初始化,不会触发SubClass的初始化,因为fatherStaticValue是FatherClass的变量

2.通过数组定义类引用类,SuperClass[] array = new SuperClass[10];

不会触发SuperClass类的初始化,但是执行字节码指令newarray会触发另外一个类[Lorg.fenixsoft.classloading.SuperClass的初始化,这个类继承于Object类,是一个包装类,里面包含了访问数组的所有方法,

3.只引用类的常量不会触发初始化,因为常量在编译阶段进入常量池

class SuperClass { public static final String str = "hello"; } //引用常量编译时会直接存入常量池 System.out.println(SuperClass.str); 点击复制代码复制出错复制成功

对于接口来说,只有在某个接口声明的非常量字段被使用时,该接口才会初始化,而不会因为事先这个接口的子接口或类要初始化而被初始化。

父类需要在子类初始化之前被初始化。当实现了接口的类被初始化的时候,不需要初始化父接口。然而,当实现了父接口的子类(或者是扩展了父接口的子接口)被装载时,父接口也要被装载。(只是被装载,没有初始化)

验证

确认装载后的类型符合Java语言的语义,并且不会危及虚拟机的完整性。

准备

在准备阶段,Java虚拟机为类变量分配内存,设置默认初始值。但在到到初始化阶段之前,类变量都没有被初始化为真正的初始值。

类型 默认值
int 0
long 0L
short (short)0
char ’\u0000’
byte (byte)0
blooean false
float 0.0f
double 0.0d
reference null

解析

解析的过程就是在类型的常量池总寻找类、接口、字段和方法的符号引用,把这些符号引用替换为直接引用的过程。

初始化

所有的类变量(即静态量)初始化语句和类型的静态初始化器都被Java编译器收集在一起,放到一个特殊的方法中,这个步骤就是初始化类静态变量和执行静态代码块。 对于类来说,这个方法被称作类初始化方法;对于接口来说,它被称为接口初始化方法。在类和接口的 class 文件中,这个方法被称为。

  1. 如果存在直接父类,且直接父类没有被初始化,先初始化直接父类。
  2. 如果类存在一个类初始化方法,执行此方法。

这个步骤是递归执行的,即第一个初始化的类一定是Object。

Java虚拟机必须确保初始化过程被正确地同步。 如果多个线程需要初始化一个类,仅仅允许一个线程来进行初始化,其他线程需等待。

这个特性可以用来写单例模式。

Clinit 方法

上一篇 下一篇

猜你喜欢

热点阅读