Class 文件的魔数和文件版本号
一 Class 文件数据类型
数 据类型 | 定义 | 说明 |
无符号数 | 无符号数可以用来描述数字、索引引用、数量值或按照 utf-8 编码构成的字符串值。 | 其中无符号数属于基本的数据类型。 以 u1、u2、u4、u8 来分别代表 1 个字节、2 个字节、4 个字节和 8 个字节 |
表 | 表是由多个无符号数或其他表构成的复合数据结构。 | 所有的表都以“_info”结尾。 由于表没有固定长度,所以通常会在其前面加上个数说明。 |
二 魔数
每个 Class 文件开头的 4 个字节的无符号整数称为魔数(Magic Number)
它的唯一作用是确定这个文件是否为一个能被虚拟机接受的有效合法的 Class 文件。即:魔数是 Class 文件的标识符。
魔数值固定为 0xCAFEBABE。不会改变。
如果一个 Class 文件不以 0xCAFEBABE 开头,虚拟机在进行文件校验的时候就会直接抛出以下错误:
Error: A JNI error has occurred, please check your installation and try again
Exception in thread “main” java.lang.ClassFormatError: Incompatible magic value 1885430635 in class file StringTest
使用魔数而不是扩展名来进行识别主要是基于安全方面的考虑,因为文件扩展名可以随意地改动。
三 文件版本号
紧接着魔数的 4 个字节存储的是 Class 文件的版本号。同样也是 4 个字节。第 5 个和第 6 个字节所代表的含义就是编译的副版本号 minor_version,而第 7 个和第 8 个字节就是编译的主版本号 major_version。
它们共同构成了 class 文件的格式版本号。譬如某个 Class 文件的主版本号为 M,副版本号为 m,那么这个 Class 文件的格式版本号就确定为 M.m。
版本号和 Java 编译器的对应关系如下表:
主版本(十进制) | 副版本(十进制) | 编译器版本 |
45 | 3 | 1.1 |
46 | 0 | 1.2 |
47 | 0 | 1.3 |
48 | 0 | 1.4 |
49 | 0 | 1.5 |
50 | 0 | 1.6 |
51 | 0 | 1.7 |
52 | 0 | 1.8 |
53 | 0 | 1.9 |
54 | 0 | 1.10 |
55 | 0 | 1.11 |
Java 的版本号是从 45 开始的,JDK1.1 之后的每个 JDK 大版本发布主版本号向上加 1。
不同版本的 Java 编译器编译的 Class 文件对应的版本是不一样的。目前,高版本的 Java 虚拟机可以执行由低版本编译器生成的 Class 文件,但是低版本的 Java 虚拟机不能执行由高版本编译器生成的 Class 文件。否则 JVM 会抛出 java.lang.UnsupportedClassVersionError 异常。(向下兼容)
在实际应用中,由于开发环境和生产环境的不同,可能会导致该问题的发生。因此,需要我们在开发时,特别注意开发编译的 JDK 版本和生产环境中的 JDK 版本是否一致。
虚拟机 JDK 版本为 1.k(k>=2)时,对应的 class 文件格式版本号的范围为 45.0 - 44+k.0(含两端)。
四 魔数和文件版本号解析
五 实战
1 代码
public class StringTest {
public static void main(String[] args) {
String str = new String("hello") + new String("world");
String str1 = "helloworld";
System.out.println(str == str1);
String str2 = new String("helloworld");
System.out.println(str == str2);
}
public void method1(){
}
public void method1(int num){
}
}
2 生成JDK8的Class文件
3 在 JRE 为 1.7的环境下运行
D:\ProgramFiles\Java\jdk1.7.0_80\bin\java.exe -javaagent
\ProgramFiles\JetBrains\IDEA\lib\idea_rt.jar=53835
\ProgramFiles\JetBrains\IDEA\bin -Dfile.encoding=UTF-8 -classpath D:\ProgramFiles\Java\jdk1.7.0_80\lib\ant-javafx.jar;D:\ProgramFiles\Java\jdk1.7.0_80\lib\dt.jar;D:\ProgramFiles\Java\jdk1.7.0_80\lib\javafx-doclet.jar;D:\ProgramFiles\Java\jdk1.7.0_80\lib\javafx-mx.jar;D:\ProgramFiles\Java\jdk1.7.0_80\lib\jconsole.jar;D:\ProgramFiles\Java\jdk1.7.0_80\lib\sa-jdi.jar;D:\ProgramFiles\Java\jdk1.7.0_80\lib\tools.jar;E:\jvmp2\out\production\jvmp2;D:\mvn_repo\junit\junit\4.12\junit-4.12.jar;D:\mvn_repo\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar chapter01.java.StringTest
java.lang.UnsupportedClassVersionError: chapter01/java/StringTest : Unsupported major.minor version 52.0
at java.lang.ClassLoader.defineClass1(Native Method)
at java.lang.ClassLoader.defineClass(ClassLoader.java:800)
at java.security.SecureClassLoader.defineClass(SecureClassLoader.java:142)
at java.net.URLClassLoader.defineClass(URLClassLoader.java:449)
at java.net.URLClassLoader.access$100(URLClassLoader.java:71)
at java.net.URLClassLoader$1.run(URLClassLoader.java:361)
at java.net.URLClassLoader$1.run(URLClassLoader.java:355)
at java.security.AccessController.doPrivileged(Native Method)
at java.net.URLClassLoader.findClass(URLClassLoader.java:354)
at java.lang.ClassLoader.loadClass(ClassLoader.java:425)
at sun.misc.Launcher$AppClassLoader.loadClass(Launcher.java:308)
at java.lang.ClassLoader.loadClass(ClassLoader.java:358)
at sun.launcher.LauncherHelper.checkAndLoadMain(LauncherHelper.java:482)
Exception in thread “main”
Process finished with exit code 1
4 在 JRE 为 1.11 环境下运行
D:\ProgramFiles\Java\jdk-11.0.11\bin\java.exe -javaagent
\ProgramFiles\JetBrains\IDEA\lib\idea_rt.jar=53768
\ProgramFiles\JetBrains\IDEA\bin -Dfile.encoding=UTF-8 -classpath E:\jvmp2\out\production\jvmp2;D:\mvn_repo\junit\junit\4.12\junit-4.12.jar;D:\mvn_repo\org\hamcrest\hamcrest-core\1.3\hamcrest-core-1.3.jar chapter01.java.StringTest
false
false
还没有评论,来说两句吧...