javap


字节码的基本信息


public class Test {
private int age = 10; public int getAge() {
return age;
}
}
  • 在 class 文件的同级目录下输入命令 javap -v -p Test.class 来查看一下输出的内容
// 字节码文件的位置
Classfile /D:/Code/code/JavaCode/JavaSourceLearn/out/production/JavaSourceLearn/test/JVM/Test.class
// 文件的修改日期和大小
Last modified 2024年7月15日; size 369 bytes
// 字节码文件的 SHA-256 值,用于校验文件的完整性
SHA-256 checksum ece86f04e47d4ba3e27fc08cf3cb675a31670d9eab284fc0b2e8487ed8ed1c73
// 该字节码文件编译自 Main.java 源文件
Compiled from "Test.java"
// 类访问修饰符和类型,表明这是一个公开的类,名为test.JVM.Test
public class test.JVM.Test
// 次版本号
minor version: 0
// 主版本号 由 Java 8 编译
major version: 52
// 类访问标记:表明当前类是 ACC_PUBLIC | ACC_SUPER(表明这个类是 public 的,并且使用了 super 关键字)。
flags: (0x0021) ACC_PUBLIC, ACC_SUPER
// 当前类的索引,指向常量池中下标为 3 的常量,当前类是 Test 类
this_class: #3 // test/JVM/Test
// 父类的索引,指向常量池中下标为 4 的常量,当前类的父类是 Object 类
super_class: #4 // java/lang/Object
// 当前类有 0 个接口,1 个字段(age),2 个方法(getAge()方法和缺省的默认构造方法),1 个属性(该类仅有的一个属性是 SourceFIle,包含了源码文件的信息)。
interfaces: 0, fields: 1, methods: 2, attributes: 1
// 常量池
Constant pool:
// 类型为 Methodref,表明是用来定义方法的,指向常量池中下标为 4 和 18 的常量
#1 = Methodref #4.#18 // java/lang/Object."<init>":()V
// 类型为 Fieldref,表明是用来定义字段的,指向常量池中下标为 3 和 19 的常量
#2 = Fieldref #3.#19 // test/JVM/Test.age:I
// 类型为 Class,表明是用来定义类(或者接口)的,指向常量池中下标为 20 的常量
#3 = Class #20 // test/JVM/Test
// 类型为 Class,表明是用来定义类(或者接口)的,指向常量池中下标为 21 的常量
#4 = Class #21 // java/lang/Object
// 类型为 Utf8,UTF-8 编码的字符串,值为 age,表明字段名为 age
#5 = Utf8 age
// 类型为 Utf8,UTF-8 编码的字符串,值为 I,表明字段的类型为 int
#6 = Utf8 I
// 类型为 Utf8,UTF-8 编码的字符串,值为 <init>,表明为构造方法
#7 = Utf8 <init>
// 类型为 Utf8,UTF-8 编码的字符串,值为 ()V,表明方法的返回值为 void
#8 = Utf8 ()V
#9 = Utf8 Code
#10 = Utf8 LineNumberTable
#11 = Utf8 LocalVariableTable
#12 = Utf8 this
#13 = Utf8 Ltest/JVM/Test;
#14 = Utf8 getAge
#15 = Utf8 ()I
#16 = Utf8 SourceFile
#17 = Utf8 Test.java
// 类型为 NameAndType,表明是字段或者方法的部分符号引用,指向常量池中下标为 7 和 8 的常量
#18 = NameAndType #7:#8 // "<init>":()V
// 类型为 NameAndType,表明是字段或者方法的部分符号引用,指向常量池中下标为 5 和 6 的常量
#19 = NameAndType #5:#6 // age:I
#20 = Utf8 test/JVM/Test
// 类型为 Utf8,UTF-8 编码的字符串,值为 java/lang/Object
#21 = Utf8 java/lang/Object
{
// 字段表
private int age;
descriptor: I
flags: (0x0002) ACC_PRIVATE
// 方法表
// 构造方法,返回类型为 void,访问标志为 public
public test.JVM.Test();
descriptor: ()V
flags: (0x0001) ACC_PUBLIC
Code:
// stack 为最大操作数栈,Java 虚拟机在运行的时候会根据这个值来分配栈帧的操作数栈深度
// locals 为局部变量所需要的存储空间,单位为槽(slot),方法的参数变量和方法内的局部变量都会存储在局部变量表中;局部变量表的容量以变量槽为最小单位,一个变量槽可以存放一个 32 位以内的数据类型,比如 boolean、byte、char、short、int、float、reference 和 returnAddress 类型;局部变量表所需的容量大小是在编译期间完成计算的,大小由编译器决定;对于实例方法(如构造方法),局部变量表的第一个位置(索引 0)总是用于存储 this 引用
// args_size 为方法的参数个数,有一个隐藏的 this 变量
stack=2, locals=1, args_size=1
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: bipush 10
7: putfield #2 // Field age:I
10: return
// 描述源码行号与字节码行号(字节码偏移量)之间的对应关系
LineNumberTable:
line 4: 0
line 5: 4
// LocalVariableTable描述帧栈中的局部变量与源码中定义的变量之间的关系
LocalVariableTable:
// Start 和 Length:定义变量在方法中的作用域。Start 是变量生效的字节码偏移量,Length 是它保持活动的长度。
// Slot:变量在局部变量数组中的索引
// Name:变量的名称,如在源代码中定义的
// Signature:变量的类型描述符
Start Length Slot Name Signature
0 11 0 this Ltest/JVM/Test;
// 成员方法
public int getAge();
descriptor: ()I
flags: (0x0001) ACC_PUBLIC
Code:
// 最大操作数栈为 1,局部变量所需要的存储空间为 1,方法的参数个数为 1,是因为局部变量只有一个隐藏的 this,并且字节码指令中只执行了一次 aload_0
stack=1, locals=1, args_size=1
// 加载 this 引用到栈顶,以便接下来访问实例字段 age
0: aload_0
// 获取字段值。这条指令读取 this 对象的 age 字段的值,并将其推送到栈顶。#2 是对常量池中的字段引用。
1: getfield #2 // Field age:I
// 返回栈顶整型值。这里返回的是 age 字段的值
4: ireturn
LineNumberTable:
line 8: 0
LocalVariableTable:
Start Length Slot Name Signature
0 5 0 this Ltest/JVM/Test;
}
SourceFile: "Test.java"
  • Java 虚拟机是在加载字节码文件的时候才进行的动态链接,也就是说,字段和方法的符号引用只有经过运行期转换后才能获得真正的内存地址。当 Java 虚拟机运行时,需要从常量池获取对应的符号引用,然后在类创建或者运行时解析并翻译到具体的内存地址上。

  • Test类使用的是默认的构造方法,来源于 Object 类。#4 指向 Class #21(即 java/lang/Object),#18 指向 NameAndType #7:#8(即 <init>:()V)。

  • 声明了一个类型为 int 的字段 age。#3 指向 Class #20(即 test/JVM/Test),#19 指向 NameAndType #5:#6(即 age:I

标识字符 含义
B 基本数据类型 byte
C 基本数据类型 char
D 基本数据类型 double
F 基本数据类型 float
I 基本数据类型 int
J 基本数据类型 long
S 基本数据类型 short
Z 基本数据类型 boolean
V 特殊类型 void
L 引用数据类型,以分号“;”结尾
[ 一维数组

字段表集合


  • 字段表用来描述接口或者类中声明的变量,包括类变量和成员变量,但不包含声明在方法中局部变量

字段的修饰符一般有:

  • 访问权限修饰符,比如 public private protected
  • 静态变量修饰符,比如 static
  • final
  • 并发可见性修饰符,比如 volatil序列化修饰符,比如 transient

然后是字段的类型(可以是基本数据类型、数组和对象)和名称。

方法表集合

  • 方法表用来描述接口或者类中声明的方法,包括类方法和成员方法,以及构造方法

javap和字节码的更多相关文章

  1. 001-Eclipse、idea集成javap查看字节码、javap说明

    一.概述 分析java语言特性的一个好帮手是使用javap工具查看java编译后的字节码,如何在eclipse中配置javap工具快速查看java字节码. 二.Eclipse集成javap查看字节码 ...

  2. Eclipse集成javap查看字节码

    分析java语言特性的一个好帮手是使用javap工具查看java编译后的字节码,楼主今天在学习java泛型中的桥方法时遇到一些不解,想到javap这个好工具可以帮助解答一些疑惑,索性就捣鼓如何在ecl ...

  3. Javap -c 字节码解析

              栈和局部变量操作 将常量压入栈的指令 aconst_null         将null对象引用压入栈   iconst_m1         将int类型常量-1压入栈 icon ...

  4. javap -c 字节码含义

    aconst_null         将null对象引用压入栈 iconst_m1         将int类型常量-1压入栈 iconst_0         将int类型常量0压入栈 icons ...

  5. 命令查看java的class字节码文件、verbose、synchronize、javac、javap

    查看Java字节码 1 javac –verbose查看运行类是加载了那些jar文件 HelloWorld演示: public class Test { public static void main ...

  6. Java Class 字节码文件结构详解

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

  7. 命令查看java的class字节码文件

    源代码: public class Math { public static void main(String[] args){ int a=1; int b=2; int c=(a+b)*10; } ...

  8. java字节码速查笔记

    java字节码速查笔记  发表于 2018-01-27 |  阅读次数: 0 |  字数统计: |  阅读时长 ≍ 执行原理 java文件到通过编译器编译成java字节码文件(也就是.class文件) ...

  9. Java并发编程原理与实战八:产生线程安全性问题原因(javap字节码分析)

    前面我们说到多线程带来的风险,其中一个很重要的就是安全性,因为其重要性因此,放到本章来进行讲解,那么线程安全性问题产生的原因,我们这节将从底层字节码来进行分析. 一.问题引出 先看一段代码 packa ...

  10. @使用javap反编译Java字节码文件

    在Sun公司提供的JDK中,就已经内置了Java字节码文件反编译工具javap.exe(位于JDK安装目录的bin文件夹下). 我们可以在dos窗口中使用javap来反汇编指定的Java字节码文件.在 ...

随机推荐

  1. Longley数据集——强共线性的宏观经济数据,包含GNP deflator(GNP平减指数)、GNP(国民生产总值)、Unemployed(失业率)、ArmedForces(武装力量)、Population(人口)、year(年份),Emlpoyed(就业率)。LongLey数据集因存在严重的多重共线性问题,在早期经常用来检验各种算法或计算机的计算精度

    Longley数据集来自J.W.Longley(1967)发表在JASA上的一篇论文,是强共线性的宏观经济数据,包含GNP deflator(GNP平减指数).GNP(国民生产总值).Unemploy ...

  2. .NET电子邮件高效处理解决方案

    前言 在日常软件开发中,电子邮件处理是一个不可或缺的功能,无论是用户注册验证.通知推送还是日常的业务沟通,都离不开电子邮件的支持.今天大姚给大家分享2款.NET开源.高效.强大的.NET电子邮件处理库 ...

  3. AtCoder Beginner Contest 329 F

    AtCoder Beginner Contest 329F F - Colored Ball (atcoder.jp)(启发式合并) 问题陈述 有 \(N\) 个编号为 \(1, 2, \ldots, ...

  4. 《重学Java设计模式》笔记——建造者模式

    1. 建造者模式可以解决什么问题 我家里有各种形状的瓷器,盘子或者碗.虽然形状不同,但是所用的材料基本上是一样的,比如土.水.釉.彩这些基本的东西. 但是做不同款式的瓷器,方法是不同的.假如说我现在已 ...

  5. 首次在WebAPI中写单元测试

    xUnit 这次我使用的是xUnit测试框架,而不是VS自带的MSTest框架.在添加新建项目时选择xUnit测试项目就行了. 目前只体验到了一个差别,即xUnit可以使用特性向测试方法传参,而不用在 ...

  6. Atcoder ABC364 D-F

    Atcoder ABC364 D-F D - K-th Nearest 链接: D - K-th Nearest (atcoder.jp) 简要题意: 问题陈述 在一条数线上有 \(N+Q\) 个点 ...

  7. Microsoft Build 2023 After Party (Placeholder)

    一年过去了,微软BUILD又回来了! https://build.microsoft.com/en-US/home This is a placeholder page for Microsoft B ...

  8. 【原创】VSCode 快捷键汇总(已整理成一张 A4 纸大小,方便打印)

    由于经常记不住 VSCode 的快捷键,每次查找不方便,于是乎做了一份 VSCode 快捷键汇总,已整理成一张 A4 纸大小,方便打印,这样查找就直观多了~ 直接保存图片,横向打印即可.

  9. 在 Mac 上使用 X11

    有时我们需要在服务器上运行一个 GUI 程序,然而我们是通过 SSH 连接到服务器的,看不到图形界面,怎么办呢?我们可以通过 X11 将 GUI 程序的界面转发到本地. 在 Mac 上使用 X11 需 ...

  10. C++ weak_ptr除了解决循环引用还能做什么?

    C++: weak_ptr到底有什么用? 很多人对std::weak_ptr的认识只是不增加std::shared_ptr的引用计数,可以用来解决std::shared_ptr可能造成的循环引用问题. ...