一. 整体结构
ClassFile {
u4 magic;
u2 minor_version;
u2 major_version;
u2 constant_pool_count;
cp_info constant_pool[constant_pool_count-1];
u2 access_flags;
u2 this_class;
u2 super_class;
u2 interfaces_count;
u2 interfaces[interfaces_count];
u2 fields_count;
field_info fields[fields_count];
u2 methods_count;
method_info methods[methods_count];
u2 attributes_count;
attribute_info attributes[attributes_count];
}
备注:u表示字节数,u4表示4个字节,u2表示2个字节
二. 示例
示例代码:
package com.yu.jvm;
public class TestClass {
public static void main(String[] args) {
}
}
使用bined(idea插件)打开class文件:
我们根据16进制字节流和字节码整体结构来对应一下
| 定义 | 字节码值 | 备注 |
|---|---|---|
| u4 magic | CA FE BA BE | 所有class的开头都是以CAFE BABE开始 |
| u2 minor version | 00 00 | 小版本号:0 |
| u2 major version | 00 34 | 大版本号:52(表示是jdk1.8) |
| u2 constant_pool_count | 00 14 | 常量池常量数量是20 - 1 = 19个 |
| cp_info | 19个常量 | |
| u2 access_flags | 00 21 | 位于0F0行,0C列,0020表示super,0001表示public |
| u2 this_class | 00 02 | 表示指向常量池中的第2个常量 |
| u2 super_class | 00 03 | 指向常量池中第3个常量 |
| u2 interfaces_count | 00 00 | 表示没有实现接口 |
| u2 interfaces[interfaces_count] | 00 00 | 空数组 |
| u2 field_count | 00 00 | 成员变量数量 |
| field_info fields[fields_count] | 变量信息 | |
| u2 methods_count | 00 02 | 2个方法:psvm方法,init方法 |
| method_info methods[methods_count] | 方法信息 | |
| u2 attributes_count | 00 01 | 属性数量 |
| attribute_info attributes[attributes_count] | 00 0F | 属性信息,指向常量池15号 |
使用javap -v 打开
Classfile /C:/Users//IdeaProjects/TestDemo/out/production/TestDemo/com/yu/jvm/TestClass.class
Last modified 2022-5-6; size 392 bytes
MD5 checksum ea651574c357b81298e8df2ce3683d60
Compiled from "TestClass.java"
public class com.yu.jvm.TestClass
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #3.#17 // java/lang/Object."<init>":()V
#2 = Class #18 // com/yu/jvm/TestClass
#3 = Class #19 // java/lang/Object
#4 = Utf8 <init>
#5 = Utf8 ()V
#6 = Utf8 Code
#7 = Utf8 LineNumberTable
#8 = Utf8 LocalVariableTable
#9 = Utf8 this
#10 = Utf8 Lcom/yu/jvm/TestClass;
#11 = Utf8 main
#12 = Utf8 ([Ljava/lang/String;)V
#13 = Utf8 args
#14 = Utf8 [Ljava/lang/String;
#15 = Utf8 SourceFile
#16 = Utf8 TestClass.java
#17 = NameAndType #4:#5 // "<init>":()V
#18 = Utf8 com/yu/jvm/TestClass
#19 = Utf8 java/lang/Object
{
public com.yu.jvm.TestClass();
descriptor: ()V
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: return
LineNumberTable:
line 3: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/yu/jvm/TestClass;
public static void main(java.lang.String[]);
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=0, locals=1, args_size=1
0: return
LineNumberTable:
line 7: 0
LocalVariableTable:
Start Length Slot Name Signature
0 1 0 args [Ljava/lang/String;
}
SourceFile: "TestClass.java"
使用jclaaslib打开(版本较老)
三. 总结
可以基于上述了解字节码文件的整体结构,对通过javac编译出来的class文件有个大致的认知即可。对于字节码指令,使用方式等等可以在需要的时候可以查看资料了解,java8的字节码文档docs.oracle.com/javase/spec…