编译的.class文件,可以用javap进行反编译

javap Test.class

javap -c Test.class

javap -verbose Test.class

1、创建MyTest1.java

public class MyTest1 {
private int a = 1; public MyTest1() {
} public int getA() {
return this.a;
} public void setA(int a) {
this.a = a;
}
}

使用D:\workspace\study\ jvm_demo\build\classes\java\main\com\example\jvm\bytecode>javap -verbose  MyTest1.class

Classfile /D:/workspace/study/ jvm_demo/build/classes/java/main/com/example/jvm/bytecode/MyTest1.class
Last modified 2019-6-23; size 495 bytes
MD5 checksum 54c0850cfabb7f115919c93e556e3630
Compiled from "MyTest1.java"
public class com.example.jvm.bytecode.MyTest1
SourceFile: "MyTest1.java"
minor version: 0
major version: 51
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#20 // java/lang/Object."<init>":()V
#2 = Fieldref #3.#21 // com/example/jvm/bytecode/MyTest1.a:I
#3 = Class #22 // com/example/jvm/bytecode/MyTest1
#4 = Class #23 // java/lang/Object
#5 = Utf8 a
#6 = Utf8 I
#7 = Utf8 <init>
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Lcom/example/jvm/bytecode/MyTest1;
#14 = Utf8 getA
#15 = Utf8 ()I
#16 = Utf8 setA
#17 = Utf8 (I)V
#18 = Utf8 SourceFile
#19 = Utf8 MyTest1.java
#20 = NameAndType #7:#8 // "<init>":()V
#21 = NameAndType #5:#6 // a:I
#22 = Utf8 com/example/jvm/bytecode/MyTest1
#23 = Utf8 java/lang/Object
{
public com.example.jvm.bytecode.MyTest1();
flags: ACC_PUBLIC
Code:
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: iconst_1
6: putfield #2 // Field a:I
9: return
LineNumberTable:
line 6: 0
line 8: 4
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this Lcom/example/jvm/bytecode/MyTest1; public int getA();
flags: ACC_PUBLIC
Code:
stack=1, locals=1, args_size=1
0: aload_0
1: getfield #2 // Field a:I
4: ireturn
LineNumberTable:
line 12: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Lcom/example/jvm/bytecode/MyTest1; public void setA(int);
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: iload_1
2: putfield #2 // Field a:I
5: return
LineNumberTable:
line 16: 0
line 17: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 this Lcom/example/jvm/bytecode/MyTest1;
0 6 1 a I
}

  

2、使用WinHex打开MyTest1.class文件

1、使用javap -verbose命令分析一个字节码文件时,将会分析该字节码文件的魔数、版本号、常量池、类的构造方法、类中的方法信息、类变量与成员变量等信息。
2、魔数: 所有的.class字节码文件的前4个字节都是魔数,魔数值为固定值: 0xCAFEBABE.
3、魔数之后的四个字节为版本信息,前两个字节表示minor version(次版本号),后两个字节表示major version(主版本号)。这里的版本号为 00 00 00 33,换算成十进制,表示次版本为0,主版本为51. (51代表JDK7). 所有该文件的版本号为: 1.7.0
4、常量池(constant pool): 紧接着主版本号之后的就是常量池入口。一个Java类中定义的很多信息都是由常量池来维护和描述的,可以将常量池看作是Class文件的资源仓库,比如说Java类中定义的方法与变量信息,都是存储在常量池中。常量池主要存储两类常量: 字面量与符号引用。字面量如文本字符串,Java中声明为final的 常量值等,而符号引用如类和接口的全局限定名,字段的名称和描述符,方法的名称和描述符等。
5、常量池的总体结构: Java类所对应常量池主要由常量池数量与常量池数组(常量表)这两部分共同构成。常量池数量紧跟在主版本号后面,占据2个字节; 常量池数组则紧跟在常量池数量之后。常量池数组与一般的数组不同的是,常量池数组中不同的元素的类型、结构都是不同的,长度当然也是不同; 但是,每一种元素的第一个数据都是一个u1类型,该字节是标志位,占据1个字节。JVM在解析常量池时,会根据这个u1类型来获取元素的具体类型。值得注意的是,常量池数组中元素的个数 = 常量池数 - 1 (其中0暂时不使用), 目的是满足某些常量池索引值的数据在特定情况下需要表单[不引用任何一个常量池]的含义 ; 根本原因在于,索引为0也是一个常量(保留常量),只不过它不位于常量表中,这个常量就对应null值; 所以常量池的索引从1而非0开始。
6、在JVM规范中,每个变量/字段都有描述信息,描述信息主要的作用是描述字段的数据类型、方法的参数列表(包括数量、类型与顺序)与返回值。根据描述规则,基本数据类型和代表无返回值的void类型都用一个大写字符来表示,对象类型则使用字符L加对象的全限定名称来表示。为了压缩字节码文件的体积,对于基本数据类型,JVM都只使用一个大写字母来表示,如下所示B - byte, C - char, D - double, F - float, I - int, J - long, S - short, Z -boolean, V -void, L -对象类型, 如Ljava/lang/String;
7、对于数组来说,每一个维度使用一个前置的[来表示,如int[]被记录为[I, String[][]被记录为[[Ljava/lang/String
8、用描述符描述方法时,按照先参数列表,后返回值的顺序来描述。参数列表按照参数的严格顺序放在一组()之内,如方法String getRealnamebyIdAndNickname(int id, String name)的描述符为:(I,Ljava/lang/String;) Ljava/lang/String;

3、Class文件结构中常量池中11种数据类型的结构总表

上面的表中描述了11中数据类型的结构,其实在jdk1.7之后又增加了3种

CONSTANT_MethodHandle_info, CONSTANT_MethodType_info 以及CONSTANT_InvokeDynamic_info) 这样总共14种。

4、Java字节码整体结构

Access_Flag访问标志: 访问标志信息包括该Class文件是类还是接口,是否被定义成public,是否是abstract,如果是类,是否被声明成final。通过上面的MyTest1源代码,我们知道该文件是类并且是public。

0x 00 21: 是0x 0020 和 0x0001的并集,表示ACC_PUBLIC与ACC_SUPER

Fields字段表集合: 字段表用于描述类和接口中声明的变量。这里的字段包含了类级别变量(静态变量)以及实例变量(成员变量),但是不包含方法内声明的局部变量

 字段表结构

 field_info

5、Java字节码整体结构

在Class文件的定义

6、Class字节码中有两种数据类型

1)字节数据直接量: 这是基本的数据类型。共细分为u1,u2,u4,u8四种,分别代表连续的1个字节,2个字节,4个字节,8个字节组成的整体数据。

2)表(数组): 表是由多个基本数据或其它表,按照既定顺序组成的大的数据集合。表是有结构的,它的结构体现在: 组成表的成分所在的位置和顺序都是已经严格定义好的。

最新文章

  1. 如何查看项目svn路径
  2. 响应式网站通用css
  3. ARM汇编程序基本知识
  4. 淘宝初始化css代码
  5. Bootstrap配套的js框架
  6. mysql --The MEMORY Storage Engine--官方文档
  7. Servlet课程0426(八)Servlet分页技术
  8. JavaScript入门(9)
  9. 【JAVA - SSM】之MyBatis的ParameterType的使用
  10. ndk编译时的通用Android.mk文件
  11. Python学习笔记3(数据结构)
  12. 支持iOS9 Universal links遇到的问题
  13. Gradle 1.12 翻译——第十六章. 使用文件
  14. 使用Egret Conversion 转化as代码到ts代码
  15. ActionBar+Fragment实现顶部标签页
  16. 移动端h5实现复制功能
  17. 前端路由简介以及vue-router实现原理
  18. CentOS 7 install slurm cluster
  19. Java-Runoob-高级教程-实例-方法:02. Java 实例 – 输出数组元素
  20. C++的命名空间的使用

热门文章

  1. 解决linux下创建用户时出现 Creating mailbox file: 文件已存在
  2. 【DRF框架】REST风格
  3. python两则99乘法表
  4. [centos][yum] centos升级到特定版本
  5. linux 利用LDAP身份集中认证
  6. Visio 撤销按钮无法使用 菜单显示:无法撤销
  7. springboot错误: 找不到或无法加载主类
  8. Problem E: 数量的类模板
  9. STL用法之set
  10. Spring -08 -自动注入 -byName/byType/constructor -全局使用default-autowire=” byName&quot;