Class文件数据类型
Class文件是一组以(8位bit的)byte字节为基础单位的二进制流。
根据Java虚拟机规范的规定,Class文件格式采用一种类似于C语言结构体的伪结构来存储数据,这种伪结构中只有两种数据类型:无符号数和表。
无符号数:无符号数属于基本的数据类型,以u1、u2、u4、u8来分别代表1个字节、2个字节、4个字节和8个字节;
无符号数可以用来描述数字、索引引用、数量值或者按照UTF-8编码构成的字符串值。
表:表是由多个无符号数或者其他表作为数据项构成的复合数据类型,所有表都习惯性地以“info”结尾。表用于描述
有层次关系的复合结构的数据,整个Class文件本质上就是一张表。
名称 | 数据类型(无符号数/表) | 数量 |
magic(魔数) | u4 | 1 |
minor_version(次版本号) | u2 | 1 |
major_version(主版本号) | u2 | 1 |
Class文件格式示意图
上图中的u、info均表示数据类型,而不代表数据本身。
一个文件能否被Java虚拟机接受,不是通过文件的扩展名来进行识别的,而是通过魔数来进行识别.这主要是基于安全方面的考虑,因为文件的扩展名可以随意改动.而且在很多文件存储标准中都使用魔数来进行身份识别,例如图片格式。
每个Class文件的头4个字节称为魔数,它的唯一作用就是确定这个文件是否为一个能被虚拟机接受的Class文件.所有Class文件的魔数,均为:0xCAFEBABE 。
紧接着魔数的4个字节存储的是Class文件的版本号:第5和第6个字节是次版本号(Minor Version),第7和第8个字节是主版本号(Major Version)。
Java的版本号是从45开始的,JDK1.1之后的每个JDK版本发布主版本号向上加1(JDK1.0~1.1使用了45.0~45.3的版本号),高版本的JDK能向下兼容以前版本的Class文件。
下面看一段简单的代码
package com.test.jvm;public class T001_ByteCode01 {}
最简单的一个类了.使用编译工具javac或者使用eclipse、idea等自带的编译工具进行编译,编译后产生的 T001_ByteCode01.class文件,然后进入使用工具(我是用的是sublime工具)打开T001_ByteCode01.class文件。打开后文件中显示的内容如下
看到class文件的头4个字节了吧, 是不是就是"CAFE BABE",你也可以尝试打开自己的class文件看看是不是这个充满浪漫的名字呢。(记得使用十六进制打开)
Major Version (主版本号)表示当前Class文件使用的是哪个版本的jdk编译的。上图中主版本号为十六进制的0x0034,转换成十进制为52,该版本号说明该class文件可以被JDK1.8或以上的虚拟机执行。
说明:Class文件中第五、六个字节存储的是次版本号(minor version),第七、八个字节存储的是
主版本号(major version)。假设Class文件的版本号十进制下为45.3,那么major version在
十进制下为45,minor versio在十进制下则为3。
注:Class文件能够被版本号对应jdk版本(或比对应版本高)的jdk加载,不能被比对应jdk版本低的jdk加载。jdk中的版本号是从45开始的,每个jdk的target参数(如果有的话)的参数值对应一个主版本号:
jdk的target参数值 | 十进制Class版本号 |
-target 1.1 | 45 |
-target 1.2 | 46 |
-target 1.3 | 47 |
-target 1.4 | 48 |
-target 1.5 | 49 |
-target 1.6 | 50 |
-target 1.7 | 51 |
-target 1.8 | 52 |
…… |
以下为jdk版本与Class版本号详细对应信息(部分):
Jdk版本 | -target参数 | 十六进制Class版本号 | 十进制Class版本号 |
Jdk 1.1.8 | 不能带-target参数 | 00 03 00 2D | 45.3 |
Jdk 1.2.2 | 不带(默认为-target 1.1) | 00 03 00 2D | 45.3 |
Jdk 1.2.2 | -target 1.2 | 00 00 00 2E | 46.0 |
Jdk 1.3.1_19 | 不带(默认为-target 1.1) | 00 03 00 2D | 45.3 |
Jdk 1.3.1_19 | -target 1.3 | 00 00 00 2D | 47.0 |
Jdk 1.4.2_10 | 不带(默认为-target 1.2) | 00 00 00 2F | 46.0 |
Jdk 1.4.2_10 | -target 1.4 | 00 00 00 30 | 48.0 |
Jdk 1.5.0_11 | 不带(默认为-target 1.5) | 00 00 00 31 | 49.0 |
Jdk 1.5.0_11 | -target 1.4 -source 1.4 | 00 00 00 30 | 48.0 |
Jdk 1.6.0_01 | 不带(默认为-target 1.6) | 00 00 00 32 | 50.0 |
Jdk 1.6.0_01 | -target 1.5 | 00 00 00 31 | 49.0 |
Jdk 1.7.0 | 不带(默认为-target 1.7) | 00 00 00 33 | 51.0 |
Jdk 1.7.0 | -target 1.6 | 00 00 00 32 | 50.0 |
Jdk 1.7.0 | -target 1.4 -source 1.4 | 00 00 00 30 | 48.0 |
Jdk 1.8.0 | 不带(默认为-target 1.8) | 00 00 00 34 | 52.0 |
... |