欢迎来到天天爱彩票官方网站_天天爱彩票官网_天天爱彩票官网电脑版! 联系我们 网站地图

天天爱彩票官方网站_天天爱彩票官网_天天爱彩票官网电脑版

0379-65557469

可研编制
全国服务热线
0379-65557469

电话: 0379-65557469
0379-63930906
0379-63900388 
0379-63253525   
传真: 0379-65557469
地址:洛阳市洛龙区开元大道219号2幢1-2522、2501、2502、2503、2504、2505室 

可研编制
当前位置: 首页 | 咨询案例 > 可研编制

十年架构师干货总结:Java 的类加载机制

作者:admin 发布时间:2019-07-11 20:34:36 浏览次数:249
打印 收藏 关闭
字体【
视力保护色

01、字节码

在聊 Java 类加载机制之前,需求先了解一下 Java 字节码,由于它和类加载机制休戚相关。

计算机只知道 0 和 1,所以任何言语编写的程序都需求编译成机器码才干被计算机了解,然后履行,Java 也不破例。

Java 在诞生的时分喊出了一个十分牛逼的标语:“Write Once, Run Anywhere”,为了达到这个意图,Sun 公司发布了许多可以在不同渠道(Windows、Linux)上运转的 Java 虚拟机(JVM)——担任载入和履行 Java 编译后的字节码。

究竟 Java 字节码是什么姿态,咱们凭借一段简略的代码来看一看。

源码如下:

package com.cmower.java_demo;
public class Test {
public static void main(String[] args) {
System.out.println("缄默沉静王二");
}
}

代码编译通往后,经过 xxd Test.class 指令查看一下这个字节码文件。

xxd Test.class
00000000: cafe babe 0000 0034 0022 0700 0201 0019 .......4."......
00000010: 636f 6d2f 636d 6f77 6572 2f6a 6176 615f com/cmower/java_
00000020: 6465 6d6f 2f54 6573 7407 0004 0100 106a demo/Test......j
00000030: 6176 612f 6c61 6e67 2f4f 626a 6563 7401 ava/lang/Object.
00000040: 0006 3c69 6e69 743e 0100 0328 2956 0100 .....()V..
00000050: 0443 6f64 650a 0003 0009 0c00 0500 0601 .Code...........
00000060: 000f 4c69 6e65 4e75 6d62 6572 5461 626c ..LineNumberTabl

感觉有点懵逼,对不对?

懵就对了十年架构师干货总结:Java 的类加载机制。

这段字节码中的 cafe babe 被称为“魔数”,是 JVM 辨认 .class 文件的标志。文件格局的定制者可以自由挑选魔数值(只需没用过),比方说 .png 文件的魔数是 8950 4e47 。

至于其他内容嘛,可以挑选忘记了。

02、类加载进程

了解了 Java 字节码后,咱们来聊聊 Java 的类加载进程。

Java 的类加载进程可以分为 5 个阶段:载入、验证、预备、解析和初始化。这 5 个阶段一般是次序发作的,但在动态绑定的状况下,解析阶段发作在初始化阶段之后。

1)Loading(载入)

JVM 在该阶段的首要意图是将字节码从不同的数据源(可能是 class 文件、也可能是 jar 包,乃至网络)转化为二进制字节省加载到内存中,并生成一个代表该类的 java.lang.Class 方针。

2)Verification(验证)

JVM 会在该阶段对二进制字节省进行校验,只需契合 JVM 字节码标准的才干被 JVM 正确履行。该阶段是确保 JVM 安全的重要屏障,下面是一些首要的查看。

cafe bene

3)Preparation(预备)

JVM 会在该阶段对类变量(也称为静态变量, static 关键字润饰的)分配内存并初始化(对应数据类型的默许初始值,如 0、0L、null、false 等)。

也便是说,假如有这样一段代码:

public String chenmo = "缄默沉静";
public static String wanger = "王二";
public static final String cmower = "缄默沉静王二";

chenmo 不会被分配内存,而 wanger 会;但 wanger 的初始值不是“王二”而是 null 。

需求留意的是, static final 润饰的变量被称作为常量,和类变量不同。常量一旦赋值就不会改变了,所以 cmower 在预备阶段的值为“缄默沉静王二”而不是 null 。

4)Resolution(解析)

该阶段将常量池中的符号引证转化为直接引证。

what?符号引证,直接引证?

符号引证以一组符号(任何方式的字面量,只需在运用时可以无歧义的定位到方针即可)来描绘所引证的方针。

在编译时,Java 类并不知道所引证的类的实践地址,因而只能运用符号引证来替代。比方 com.Wanger 类引证了 com.Chenmo 类,编译时 Wanger 类并不知道 Chenmo 类的实践内存地址,因而只能运用符号 com.Chenmo 。

直接引证经过对符号引证进行解析,找到引证的实践内存地址。

5)Initialization(初始化)

该阶段是类加载进程的终究一步。在预备阶段,类变量现已被赋过默许初始值,而在初始化阶段,类变量将被赋值为代码希望赋的值。换句话说,初始化阶段是履行类结构器办法的进程。

oh,no,上面这段话说得很笼统,欠好了解,对不对,我来举个比方。

String cmower = new String("缄默沉静王二");

上面这段代码运用了 new 关键字来实例化一个字符串方针,那么这时分,就会调用 String 类的结构办法对 cmower 进行实例化。

03、类加载器

聊完类加载进程,就不得不聊聊类加载器。

一般来说,Java 程序员并不需求直接同类加载器进行交互。JVM 默许的行为就现已满意满意大多数状况的需求了。不过,假如遇到了需求和类加载器进行交互的状况,而对类加载器的机制又不是很了解的话,就不得不花很多的时刻去调试 ClassNotFoundException 和 NoClassDefFoundError 等反常。

关于恣意一个类,都需求由它的类加载器和这个类自身一同确认其在 JVM 中的唯一性。也便是说,假如两个类的加载器不同,即便两个类来源于同一个字节码文件,那这两个类就必定不相等(比方两个类的 Class 方针不 equals )。

站在程序员的视点来看,Java 类加载器可以分为三种。

1)发动类加载器(Bootstrap Class-Loader),加载 jre/lib 包下面的 jar 文件,比方说常见的 rt.jar。

2)扩展类加载器(Extension or Ext Class-Loader),加载 jre/lib/ext 包下面的 jar 文件。

3)运用类加载器(Application or App Clas-Loader),依据程序的类途径(classpath)来加载 Java 类。

来来来,经过一段简略的代码了解下。

publi十年架构师干货总结:Java 的类加载机制c clas虾米音乐网s Test {
public static void main(String[] args) {
ClassLoader loader = Test.class.getClassLoader();
while (loader != null) {
System.out.println(loader.toString());
loader = loader.getParent();
}
}
}

每个 Java 类都维护着一个指向界说它的类加载器的引证,经过 类名.class.getClassLoader()可以获取到此引证;然后经过 loader.getParent() 可以获取类加载器的上层类加载器。

这段代码的输出成果如下:

sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc.Launcher$ExtClassLoader@15db9742

榜首行输出为 Test 的类加载器,即运用类加载器十年架构师干货总结:Java 的类加载机制,它是 sun.misc.Launcher$AppClassLoader类的实例;第二行输出为扩展类加载器,是 sun.misc.Launcher$ExtClassLoader 类的实例。那发动类加载器呢?

按理说,扩展类加载器的上层类加载器是发动类加载器,但在我这个版别的 JDK 中, 扩展类加载器的 getParent() 回来 null 。所以没有输出。

04、双亲派遣模型

假如以上三品种加载器不能满意要求的话,程序员还可以自界说类加载器(承继 java.lang.ClassLoader 类),它们之间的层级联系如下图所示。

这种层次联系被称作为 双亲派遣模型 :假如一个类加载器收到了加载类的恳求,它会先把恳求托付给上层加载器去完结,上层加载器又会托付上上层加载器,一直到最顶层的类加载器;假如上层加载器无法完结类的加载作业时,当时类加载器才会测验自己去加载这个类。

PS:双亲派遣模型忽然让我联想到朱元璋同志,这个同志当上了皇帝之后连宰相都不要了,一切的工作都亲力亲为,只需自己没精力没时刻做的事才交给大臣们去干。

运用双亲派遣模型有一个很明显的优点,那便是 Java 类跟着它的类加载器一同具有了一种带有优先级的层次联系,这关于确保 Java 程序的安稳运作很重要。

上文中曾说到,假如两个类的加载器不同,即便两个类来源于同一个字节码文件,那这两个类就必定不相等——双亲派遣模型可以确保同一个类终究会被特定的类加载器加载。

05、终究

硬着头皮翻看了很多的材料,而且着手去研讨今后,我发现自己居然对 Java 类加载机制(JVM 将类的信息动态添加到内存并运用的一种机制)不那么抵抗了——真是蛮美妙的一件事啊。

或许学习就应该是这样,只需你勇于应战自己,就能收成常识——就像山就在那里,只需你肯攀爬,就能抵达山顶。

end:假如你觉得本文对你有协助的话,记住关注点赞转发,你的支撑便是我更新动力。

版权所有:洛阳市建设工程咨询有限责任公司 联系人:李经理 电话: 地址:洛阳市洛龙区开元大道219号2幢1-2522、2501、2502、2503、2504、2505室
版权所有 天天爱彩票官方网站 晋ICP备188244585号-3