Java 虚拟机程序员

【Java 虚拟机笔记】类文件结构相关整理

2019-03-05  本文已影响20人  58bc06151329

文前说明

作为码农中的一员,需要不断的学习,我工作之余将一些分析总结和学习笔记写成博客与大家一起交流,也希望采用这种方式记录自己的学习之旅。

本文仅供学习交流使用,侵权必删。
不用于商业目的,转载请注明出处。

1. 概述

2. Class 类文件结构

名称 中文名称 类型 数量
magic 魔数 u4 1
minor_version 次版本号 u2 1
major_version 主版本号 u2 1
constant_pool_count 常量池个数 u2 1
constant_pool 常量池 cp_info constant_pool_count - 1
access_flags 访问标志 u2 1
this_class 类索引 u2 1
interfaces_count 接口数量(实现的) u2 1
interfaces 接口(实现的) u2 interfaces_count
fields_count 字段个数 u2 1
fields 字段 field_info fields_count
methods_count 方法个数 u2 1
methods 方法 method_info methods_count
attributes_cound 属性个数 u2 1
attributes 属性 attribute_info attributes_cound

执行样例

public class Test {

    private static final int _1MB = 1024 * 1024;

    public static void main(String[] args) {

        byte[] allocation1, allocation2, allocation3;

        allocation1 = new byte[1 * _1MB / 4];
        allocation2 = new byte[4 * _1MB];
        allocation3 = new byte[4 * _1MB];
        allocation3 = null;
        allocation3 = new byte[4 * _1MB];
    }
}
编译后的 Class 内容

1.1 魔数(Magic Number)

1.2 版本号

版本号

1.3 常量池

常量池的项目类型 标志位 描述
CONSTANT_Utf8_info 1 UTF-8 编码的字符串。
CONSTANT_Integer_info 3 整形字面量。
CONSTANT_Float_info 4 浮点型字面量。
CONSTANT_Long_info 5 长整形字面量。
CONSTANT_Double_info 6 双精度浮点型字面量。
CONSTANT_Class_info 7 类或接口的符号引用。
CONSTANT_String_info 8 字符串类型字面量。
CONSTANT_Fieldref_info 9 字段的符号引用。
CONSTANT_Methodref_info 10 类中方法的符号引用。
CONSTANT_InterfaceMethodref_info 11 接口中方法的符号引用。
CONSTANT_NameAndType_info 12 字段或方法的部分符号引用。
CONSTANT_MethodHandle_info 15 表示方法句柄。
CONSTANT_MethodType_info 16 表示方法类型。
CONSTANT_InvokeDynamic_info 18 表示一个动态方法调用点。
常量 项目 类型 描述
CONSTANT_Utf8_info tag u1 值为 1。
length u2 UTF-8 编码字符串占用的字节数。
bytes u1 长度为 length 的 UTF-8 编码的字符串。
CONSTANT_Integer_info tag u1 值为 3。
bytes u4 按照高位在前存储的 int 值。
CONSTANT_Float_info tag u1 值为 4。
bytes u4 按照高位在前存储的 float 值。
CONSTANT_Long_info tag u1 值为 5。
bytes u8 按照高位在前存储的 long 值。
CONSTANT_Double_info tag u1 值为 6。
bytes u8 按照高位在前存储的 double 值。
CONSTANT_Class_info tag u1 值为 7。
index u2 指向全限定名常量项的索引。
CONSTANT_String_info tag u1 值为 8。
index u2 指向字符串字面量的索引。
CONSTANT_Fieldref_info tag u1 值为 9。
index u2 指向声明字段的类或者接口描述符 CONSTANT_Class_info 的索引项。
index u2 指向字段描述符 CONSTANT_NameAndType 的索引项。
CONSTANT_Methodref_info tag u1 值为 10。
index u2 指向声明方法的类描述符 CONSTANT_Class_info 的索引项。
index u2 指向名称及类型描述符 CONSTANT_NameAndType 的索引项。
CONSTANT_Interface_Methodref_info tag u1 值为 11。
index u2 指向声明方法的接口描述符 CONSTANT_Class_info 的索引项。
index u2 指向名称及类描述符 CONSTANT_NameAndType 的索引项。
CONSTANT_NameAndType_info tag u1 值为 12。
index u2 指向该字段或方法名称常量的索引。
index u2 指向该字段或方法描述符常量项的索引。
CONSTANT_MethodHandle_info tag u1 值为 15。
reference_kind u1 值必须在 [1-9],它决定了方法句柄的类型。方法句柄类型的值表示方法句柄的字节码行为。
reference_index u2 值必须是对常量池的有效索引。
CONSTANT_MethodType_info tag u1 值为 16。
descriptor_index u2 值必须是对常量池的有效索引,常量池在该索引处的项必须是 CONSTANT_Utf8_info 结构,表示方法的描述符。
CONSTANT_InvokeDynamic_info tag u1 值为 18。
bootstrap_method_attr_index u2 值必须是对当前 Class 文件中引导方法表的 bootstrap_methods[] 数组的有效索引。
name_and_type_index u2 值必须是对当前常量池的有效索引,常量池在该索引出的项必须是 CONSTANT_NameAndType_info 结构,表示方法名和方法描述符。
常量池

通过 javap 查看字节码

Constant pool:
   #1 = Methodref          #5.#27         // java/lang/Object."<init>":()V
   #2 = Class              #28            // services/Test
   #3 = Integer            262144
   #4 = Integer            4194304
   #5 = Class              #29            // java/lang/Object
   #6 = Utf8               _1MB
   #7 = Utf8               I
   #8 = Utf8               ConstantValue
   #9 = Integer            1048576
  #10 = Utf8               <init>
  #11 = Utf8               ()V
  #12 = Utf8               Code
  #13 = Utf8               LineNumberTable
  #14 = Utf8               LocalVariableTable
  #15 = Utf8               this
  #16 = Utf8               Lservices/Test;
  #17 = Utf8               main
  #18 = Utf8               ([Ljava/lang/String;)V
  #19 = Utf8               args
  #20 = Utf8               [Ljava/lang/String;
  #21 = Utf8               allocation1
  #22 = Utf8               [B
  #23 = Utf8               allocation2
  #24 = Utf8               allocation3
  #25 = Utf8               SourceFile
  #26 = Utf8               Test.java
  #27 = NameAndType        #10:#11        // "<init>":()V
  #28 = Utf8               services/Test
  #29 = Utf8               java/lang/Object

1.4 访问标志

标志名称 标志值 含义
ACC_PUBLIC 0x0001 是否为 public 类型。
ACC_FINAL 0x0010 是否被声明为 final,只有类可设置。
ACC_SUPER 0x0020 是否允许使用 invokespecial 字节码指令的新语言,invokespecial 指令的语意在 JDK 1.0.2 发生过改变,为了区别这条指令使用哪种语意,JDK 1.0.2 之后编译出来的类的这个标志都必须为真。
ACC_INTERFACE 0x0200 标识这是一个接口。
ACC_ABSTRACT 0x0400 是否为 abstract 类型,对于接口或者抽象类来说,此标志值为真,其他类值为假。
ACC_SYNTHETIC 0x1000 标识这个类并非由用户代码产生的。
ACC_ANNOTATION 0x2000 标识这是一个注解。
ACC_ENUM 0x4000 标识这是一个枚举。

1.5 类索引

1.6 父类索引

1.7 接口索引

1.8 字段表集合

名称 类型 数量 描述
access_flags u2 1 访问标志。
name_index u2 1 字段的简单名称。
descriptor_index u2 1 字段和方法的描述符。
attributes_count u2 1 属性表数量。
attributes attribute_info attributes_count 属性表。
标志名称 标志值 含义
ACC_PUBLIC 0x0001 字段是否 public。
ACC_PRIVATE 0x0002 字段是否 private。
ACC_PROTECTED 0x0004 字段是否 protected。
ACC_STATIC 0x0008 字段是否 static。
ACC_FINAL 0x0010 字段是否 final。
ACC_VOLATILE 0x0040 字段是否 volatile。
ACC_TRANSIENT 0x0080 字段是否 transient。
ACC_SYNTHETIC 0x1000 字段是否由编译器自动产生的。
ACC_ENUM 0x4000 字段是否 enum。

全限定名

简单名称

描述符

标志字符 含义
B byte
C char
D double
F float
I int
J long
S short
Z boolean
V void
L 对象类型
[ 数组

1.9 方法表集合

标志名称 标志值 含义
ACC_PUBLIC 0x0001 字段是否 public。
ACC_PRIVATE 0x0002 字段是否 private。
ACC_PROTECTED 0x0004 字段是否 protected。
ACC_STATIC 0x0008 字段是否 static。
ACC_FINAL 0x0010 字段是否 final。
ACC_SYNCHRONIZED 0x0020 方法是否为 synchronized。
ACC_BRIDGE 0x0040 方法是否由编译器产生的桥接方法。
ACC_VARARGS 0x0080 方法是否接受不定参数。
ACC_NATIVE 0x0100 方法是否为 native。
ACC_ABSTRACT 0x0400 方法是否为 abstract。
ACC_STRICTFP 0x0800 方法是否为 strictfp。
ACC_SYNTHETIC 0x1000 方法是否是由编译器自动产生的。

1.10 属性表集合

名称 类型 数量
attribute_name_index u2 1
attribute_length u4 1
sourcefile_index u2 1
属性名称 使用位置 含义
Code 方法表 Java 代码编译成的字节码指令。
ConstantValue 字段表 final 关键字定义的常量值。
Deprecated 类、方法表、字段表 被声明为 deprecated 的方法和字段。
Exceptions 方法表 方法抛出的异常。
EnclosingMethod 类文件 仅当一个类为局部类或者匿名类时才能拥有这个属性,这个属性用于标识这个类所在的外围方法。
InnerClasses 类文件 内部类列表。
LineNumberTable Code 属性 Java 源码的行号与字节码指令的对应关系。
LocalVariableTable Code 属性 方法的局部变量描述。
StackMapTable Code 属性 JDK 1.6 中新增的属性,供新的类型检查验证器(Type Checker)检查和处理目标方法的局部变量和操作数栈所需要的类型是否匹配。
Signature 类、方法表、字段表 JDK 1.5 中新增的属性,这个属性用于支持泛型情况下的方法签名,在 Java 语言中,任何类、接口,初始化方法或成员的泛型签名如果包含了类型变量(Type Variables)或参数化类型(Parameterized Type),则 Signature 属性会为它记录泛型签名信息。由于 Java 的泛型采用擦除法实现,在为了避免类型信息被擦除后导致签名混乱,需要这个属性记录泛型中的相关信息。
SourceFile 类文件 记录源文件名称。
SourceDebugExtension 类文件 JDK 1.6 中新增的属性,SourceDebugExtension 属性用于存储额外的调试信息。譬如在进行 JSP 文件调试时,无法通过 Java 堆栈来定位到 JSP 文件的行号,JSR-45 规范为这些非 Java 语言编写,却需要编译成字节码并运行在 Java 虚拟机中的程序提供了一个进行调试的标准机制,使用 SourceDebugExtension 属性就可以用于存储这个标准所新加入的调试信息。
Synthetic 类、方法表、字段表 标识方法或字段为编译器自动生成的。
LocalvariableTypeTable JDK 1.5 中新增的属性,它使用特征签名代替描述符,是为了引入泛型语法之后能描述泛型参数化类型而添加。
RuntimeVisibleAnnotations 类、方法表、字段表 JDK 1.5 中新增的属性,为动态注解提供支持。RuntimeVisibleAnnotations 属性用于指明哪些注解是运行时(实际上运行时就是进行反射调用)可见的。
RuntimeInvisibleAnnotations 类、方法表、字段表 JDK 1.5 中新增的属性,作用与 RuntimeVisibleAnnotations 属性作用刚好相反,用于指明那些注解是运行时不可见的。
RuntimeVisibeParameterAnnotations 方法表 JDK 1.5 中新增的属性,作用与 RuntimeVisibleAnnotations 属性类似,只不过作用对象为方法参数。
RuntimeInvisibeParameterAnnotations 方法表 JDK 1.5 中新增的属性,作用与 RuntimeInvisibleAnnotations 属性类似,只不过作用对象为方法参数。
AnnotationDefault 方法表 JDK 1.5 中新增的属性,用于记录注解类元素的默认值。

1.10.1 Code 属性

名称 类型 数量 含义
attribute_name_index u2 1 指向常量池中一个 CONSTANT_Utf8_info 类型的常量,表示属性名称。
attribute_length u4 1 属性值长度。
max_stack u2 1 表示操作栈深度的最大值。
max_locals u2 1 表示局部变量表所需的存储空间。
code_length u4 1 表示代码字节码长度。
code u1 code_length 用来存储字节码指令的一系列字节流。
exception_table_length u2 1 异常表长度。
exception_table exception_info exception_table_length 异常属性表。
attributes_count u2 1 Code 属性总数。
attributes attribute_info attributes_count Code 属性。

异常属性表(exception_table)

名称 类型 数量
start_pc u2 1
end_pc u2 1
handler_pc u2 1
catch_type u2 1

1.10.2 ConstantValue 属性

名称 类型 数量
attribute_name_index u2 1
attribute_length u4 1
constantValue_index u2 1

1.10.3 Deprecated 及 Synthetic 属性

名称 类型 数量
attribute_name_index u2 1
attribute_length u4 1

1.10.4 Exceptions 属性

名称 类型 数量
attribute_name_index u2 1
attribute_length u4 1
number_of_exceptions u2 1
exceptions_index_table u2 number_of_exceptions

1.10.5 InnerClasses 属性

名称 类型 数量
attribute_name_index u2 1
attribute_length u4 1
number_of_classes u2 1
inner_classes inner_classes_info number_of_classes
名称 类型 数量
inner_classes_info_index u2 1
outer_classes_info_index u2 1
inner_name_index u2 1
inner_class_access_flags u2 1
标志名称 标志值 含义
ACC_PUBLIC 0x0001 内部类是否为 public 类型。
ACC_PRIVATE 0x0002 内部类字段是否 private。
ACC_PROTECTED 0x0004 内部类字段是否 protected。
ACC_STATIC 0x0008 内部类字段是否 static。
ACC_FINAL 0x0010 内部类是否被声明为 final,只有类可设置。
ACC_INTERFACE 0x0020 内部类标识这是一个接口。
ACC_ABSTRACT 0x0400 内部类是否为 abstract 类型,对于接口或者抽象类来说,此标志值为真,其他类值为假。
ACC_SYNTHETIC 0x1000 内部类是否由用户代码产生的。
ACC_ANNOTATION 0x2000 内部类是否是一个注解。
ACC_ENUM 0x4000 内部类是否是一个枚举。

1.10.6 LineNumberTable 属性

1.10.7 LocalVariableTable 属性

1.10.8 StackMapTable 属性

名称 类型 数量
attribute_name_index u2 1
attribute_length u4 1
number_of_entries u2 1
stack_map_frame_entries stack_map_frame number_of_entries

1.10.9 SourceFile 属性

类型 名称 数量
attribute_name_index u2 1
attribute_length u4 1
sourcefile_index u2 1

参考资料

https://blog.csdn.net/u012998254/article/details/82802627
https://www.jianshu.com/p/846f93699663
https://www.cnblogs.com/zawier/p/6659311.html

上一篇 下一篇

猜你喜欢

热点阅读