首页 > 编程语言 >javap和字节码

javap和字节码

时间:2024-07-15 20:08:41浏览次数:10  
标签:常量 Utf8 age 数据类型 javap JVM Test 字节

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

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

方法表集合

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

标签:常量,Utf8,age,数据类型,javap,JVM,Test,字节
From: https://www.cnblogs.com/sprinining/p/18303875

相关文章

  • 大端小端、MSB和LSB、字节序和比特序
    CPU架构决定大小端模式_cpu架构与大小端的关系-CSDN博客常见处理器大小端_大端系统有哪些-CSDN博客大端存储、小端存储端序(英语:Endianness),又称字节顺序,又称尾序,在计算机科学领域中,指存储器中或在数字通信链路中,组成多字节的字的字节的排列顺序。大小端存储的关系主要涉及数据......
  • AI: 了解字节跳动的开源的奇迹 AnimateDiff-Lightning 文生视频大模型
    在不断发展的人工智能领域,开源贡献在推动技术进步和使前沿工具更广泛地可用方面起着至关重要的作用。字节跳动,这个科技界的知名企业,最近通过他们在HuggingFace上发布的模型AnimateDiff-Lightning,做出了重大贡献。本文将深入探讨AnimateDiff-Lightning的功能和优势,强调它为......
  • 字节面试题:在线表格功能怎么实现?怎么测?
    最近有小伙伴私信问我怎么不更新了,期待更新,甚是感动。简述下自己近况:还在干测试,最近忙活的事情大概是自动化测试、性能测试以及业务等等,主打一个啥活都干。业余时间,尝试在短视频赛道搞一些个人兴趣领域的创作,所以博客不太更新,想分享的东西还是有的,后续仍然会记录一些工作心得,感......
  • 字节跳动开启两大顶尖人才计划!内推一人一万?
    大家好,我是白露。问大家一个问题,你觉得内推一个校招生能拿到多少钱?今天从字节朋友了解到,最近字节跳动新开了一个招聘计划。内推奖励是一人至少一万。。。我都惊呆了,因为我之前了解过腾讯、快手、字节的招聘奖励。根据内推人员的级别不同,奖励从1000~6000不等。然而字节这......
  • [Java SE] 字节操作工具类:ByteUtils
    0引言与嵌入式软件数据交互过程中,必然涉及各种的、大量的字节操作场景。如:16进制与10进制、2进制间的转换,字符串、byte数组与int之间的转换等。故此有此核心工具类的沉淀。1ByteUtils依赖<properties> <!--编程提效工具--> <lombok.version>1.18.22</lombok.version>......
  • DeepViT:字节提出深层ViT的训练策略 | 2021 arxiv
    作者发现深层ViT出现的注意力崩溃问题,提出了新颖的Re-attention机制来解决,计算量和内存开销都很少,在增加ViT深度时能够保持性能不断提高来源:晓飞的算法工程笔记公众号论文:DeepViT:TowardsDeeperVisionTransformer论文地址:https://arxiv.org/abs/2103.11886论文代码......
  • Linux网络:网络字节序及socket套接字
    目录一、认识端口号二、浅谈TCP及UDP协议三、网络字节序四、socket编程4.1常见接口4.2sockAPI4.2.1sockaddr4.2.2sockaddr_in4.2.3in_addr一、认识端口号端口号(port)是传输层协议的内容.端口号是一个2字节16位的整数;端口号用来标识一个进程,告诉操......
  • C语言字节对齐技术在嵌入式、网络与操作系统中的应用与优化
    第一部分:嵌入式系统中的字节对齐嵌入式系统通常对性能和资源有着严格的要求。在这些系统中,字节对齐的正确使用可以显著提高数据访问速度,减少内存占用,并提高系统的整体效率。一、嵌入式系统中的字节对齐挑战嵌入式系统中的微处理器和微控制器通常对数据访问的对齐有特定的要......
  • 字节码文件解剖
    ####前提提要:.java文件通过java-c生成.class文件,这部分并非是JVM需要处理的部分,JVM处理的部分是基于生成的class文件,生成的部分是由编译器来负责一个字节码文件的主要组成部分使用工具说明idea的JclassLib插件使用步骤:运行代码(只要你更新了代码就需要,或者build)......
  • 字节面试 用double,1.0-0.9的结果不是0.1,为什么?
    让我详细解释一下为什么1.0-0.9在二进制中不能精确表示。1.0的二进制表示1.0在二进制中可以精确表示。它的二进制表示为:1.0=1.0(二进制)0.9的二进制表示0.9是一个无法在二进制中精确表示的小数。二进制小数是通过求和1/2,1/4,1/8,1/16,...等幂次表示的。对......