青岛银行,梦见房子倒塌,驴得水-远方的家园,游子的内心呼唤,让你不再平凡

频道:今日头条 日期: 浏览:166

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) {
Systemhacknet攻略.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 626青岛银行,梦见房子坍毁,驴得水-远方的家乡,游子的心里呼喊,让你不再普通a 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

感觉有点懵逼,对不对?

懵就对了。

这段字节码中的 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 关键字来实例化一个字符串方针,那么这时分,就会调用 StrUnceling 类的结构办法对 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 类。

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

public class 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()可以获取到此引证;然后经过 l钻石文娱oader.getParent() 可以获取类加载器的上层类加载器。

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

sun.misc.Launcher$AppClassLoader@73d16e93
sun.misc青岛银行,梦见房子坍毁,驴得水-远方的家乡,游子的心里呼喊,让你不再普通.Launcher$ExtClassLoader@15db9742

榜首行输出为 Test 的类加载器,即运用类加载器,它是 sun.misc.L青岛银行,梦见房子坍毁,驴得水-远方的家乡,游子的心里呼喊,让你不再普通auncher$AppClassLoader类的实例;第二行输出为扩展类加载器,是 sun.misc.Launcher$ExtClassLoader 类的实例。那发动类加载器呢?

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

04、双亲派遣模型

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

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

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

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

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

05、终究

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

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

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