上一节在讲 JVM 运行 Java 代码的时候,我们提到,JVM 需要将编译后的字节码文件加载到其内部的运行时数据区域中进行执行。这个过程涉及到了 Java 的类加载机制(面试常问的知识点),所以我们来详细地讲一讲。
字节码我们上一节也讲过,它和类的加载机制息息相关,相信大家都还有印象。
这里再给大家普及一个小技巧,可以通过 xxd 命令来查看字节码文件,先看下面这段代码。
public class Test {
public static void main(String[] args) {
System.out.println("沉默王二");
}
}
代码编译通过后,在命令行执行 xxd Test.class
(macOS 用户可以直接执行,Windows 用户可以戳这个链接获取替代品)就可以快速查看字节码的十六进制内容。
xxd 是一个用于在终端中创建十六进制转储(hex dump)或将十六进制转回二进制的工具。可通过维基百科了解更多信息。
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 ..<init>...()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 文件(字节码文件)的标志,相信大家都知道,Java 的 logo 是一杯冒着热气的咖啡,是不是又关联上了?
文件格式的定制者可以自由选择魔数值(只要没用过),比如说 .png 文件的魔数是
8950 4e47
。
至于字节码文件中的其他内容,暂时先不用去管,我们后面会详细讲解。
类加载过程
知道什么是 Java 字节码后,我们来聊聊 Java 的类加载过程。
类从被加载到 JVM 开始,到卸载出内存,整个生命周期分为七个阶段,分别是加载、验证、准备、解析、初始化、使用和卸载。其中验证、准备和解析这三个阶段统称为连接。
除去使用和卸载,就是 Java 的类加载过程。这 5 个阶段一般是顺序发生的,但在动态绑定的情况下,解析阶段发生在初始化阶段之后(我们随后来解释)。
1)Loading(载入)
JVM 在该阶段的目的是将字节码从不同的数据源(可能是 class 文件、也可能是 jar 包,甚至网络)转化为二进制字节流加载到内存中,并生成一个代表该类的 java.lang.Class
对象(在学反射的时候有讲过)。
2)Verification(验证)
JVM 会在该阶段对二进制字节流进行校验,只有符合 JVM 字节码规范的才能被 JVM 正确执行。该阶段是保证 JVM 安全的重要屏障,下面是一些主要的检查。
- 确保二进制字节流格式符合预期(比如说是否以
cafe bene
开头,前面提到过)。 - 是否所有方法都遵守访问控制关键字的限定,protected、private 那些。
- 方法调用的参数个数和类型是否正确。
- 确保变量在使用之前被正确初始化了。
- 检查变量是否被赋予恰当类型的值。
- 还有更多。
3)Preparation(准备)
JVM 会在该阶段对类变量(也称为静态变量,static
关键字修饰的)分配内存并初始化,对应数据类型的默认初始值,如 0、0L、null、false 等。
也就是说,假如有这样一段代码:
public String chenmo = "沉默";
public static String wanger = "王二";
public stat
回复