b java 之字节码详解

本文从一个简单的Demo类出发,深入探讨Java字节码,包括使用javap进行反编译,字节码解析,以及字节码结构的详细分析。重点关注常量类型表、类访问权限控制、字段表、方法表和属性表,特别是code、LineNumberTable和LocalVariableTable等重要属性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

—> go to 总目录

从一个class文件看字节码结构。
java虚机规范

一、Demo

1.1 Demo.java

仅有一个变量,一个方法。

package com.httpserver;

/**
 * <code>Demo</code> description
 *
 * @author sunqiyuan
 * @date 2020-04-28
 */
public class Demo {
    private int num = 1;

    public int add() {
        num = num + 2;
        return num;
    }
}

1.2 反编译的真实java文件

可以看出来多了this

在这里插入图片描述

1.3 Demo.class

00000000: cafe babe 0000 0034 0016 0a00 0400 1209  .......4........
00000010: 0003 0013 0700 1407 0015 0100 036e 756d  .............num
00000020: 0100 0149 0100 063c 696e 6974 3e01 0003  ...I...<init>...
00000030: 2829 5601 0004 436f 6465 0100 0f4c 696e  ()V...Code...Lin
00000040: 654e 756d 6265 7254 6162 6c65 0100 124c  eNumberTable...L
00000050: 6f63 616c 5661 7269 6162 6c65 5461 626c  ocalVariableTabl
00000060: 6501 0004 7468 6973 0100 154c 636f 6d2f  e...this...Lcom/
00000070: 6874 7470 7365 7276 6572 2f44 656d 6f3b  httpserver/Demo;
00000080: 0100 0361 6464 0100 0328 2949 0100 0a53  ...add...()I...S
00000090: 6f75 7263 6546 696c 6501 0009 4465 6d6f  ourceFile...Demo
000000a0: 2e6a 6176 610c 0007 0008 0c00 0500 0601  .java...........
000000b0: 0013 636f 6d2f 6874 7470 7365 7276 6572  ..com/httpserver
000000c0: 2f44 656d 6f01 0010 6a61 7661 2f6c 616e  /Demo...java/lan
000000d0: 672f 4f62 6a65 6374 0021 0003 0004 0000  g/Object.!......
000000e0: 0001 0002 0005 0006 0000 0002 0001 0007  ................
000000f0: 0008 0001 0009 0000 0038 0002 0001 0000  .........8......
00000100: 000a 2ab7 0001 2a04 b500 02b1 0000 0002  ..*...*.........
00000110: 000a 0000 000a 0002 0000 0009 0004 000a  ................
00000120: 000b 0000 000c 0001 0000 000a 000c 000d  ................
00000130: 0000 0001 000e 000f 0001 0009 0000 003d  ...............=
00000140: 0003 0001 0000 000f 2a2a b400 0205 60b5  ........**....`.
00000150: 0002 2ab4 0002 ac00 0000 0200 0a00 0000  ..*.............
00000160: 0a00 0200 0000 0d00 0a00 0e00 0b00 0000  ................
00000170: 0c00 0100 0000 0f00 0c00 0d00 0000 0100  ................
00000180: 1000 0000 0200 110a                      ........

1.4 javap -verbose

jdk自带反解析工具

Classfile /Users/sunqiyuan/Desktop/Demo.class
  Last modified 2020年4月28日; size 391 bytes
  SHA-256 checksum 91497ea9c8db954d68c9206e1c17a2251658351718284cf92d73fac35c10e8d5
  Compiled from "Demo.java"
public class com.httpserver.Demo
  minor version: 0
  major version: 52
  flags: (0x0021) ACC_PUBLIC, ACC_SUPER
  this_class: #3                          // com/httpserver/Demo
  super_class: #4                         // java/lang/Object
  interfaces: 0, fields: 1, methods: 2, attributes: 1
Constant pool:
   #1 = Methodref          #4.#18         // java/lang/Object."<init>":()V
   #2 = Fieldref           #3.#19         // com/httpserver/Demo.num:I
   #3 = Class              #20            // com/httpserver/Demo
   #4 = Class              #21            // java/lang/Object
   #5 = Utf8               num
   #6 = Utf8               I
   #7 = Utf8               <init>
   #8 = Utf8               ()V
   #9 = Utf8               Code
  #10 = Utf8               LineNumberTable
  #11 = Utf8               LocalVariableTable
  #12 = Utf8               this
  #13 = Utf8               Lcom/httpserver/Demo;
  #14 = Utf8               add
  #15 = Utf8               ()I
  #16 = Utf8               SourceFile
  #17 = Utf8               Demo.java
  #18 = NameAndType        #7:#8          // "<init>":()V
  #19 = NameAndType        #5:#6          // num:I
  #20 = Utf8               com/httpserver/Demo
  #21 = Utf8               java/lang/Object
{
  public com.httpserver.Demo();
    descriptor: ()V
    flags: (0x0001) 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 num:I
         9: return
      LineNumberTable:
        line 9: 0
        line 10: 4
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      10     0  this   Lcom/httpserver/Demo;

  public int add();
    descriptor: ()I
    flags: (0x0001) ACC_PUBLIC
    Code:
      stack=3, locals=1, args_size=1
         0: aload_0
         1: aload_0
         2: getfield      #2                  // Field num:I
         5: iconst_2
         6: iadd
         7: putfield      #2                  // Field num:I
        10: aload_0
        11: getfield      #2                  // Field num:I
        14: ireturn
      LineNumberTable:
        line 13: 0
        line 14: 10
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      15     0  this   Lcom/httpserver/Demo;
}
SourceFile: "Demo.java"

1.5 字节码解析

javap是以人类可读的方式解析字节码。
这张图把字节码进行了标注和javap的字段是一一对应的
中文版
方便快速理解
在这里插入图片描述

英文版
方便准确理解
在这里插入图片描述

1.6 字节码结构(速查)

字节码本质是一张表。一张有结构从上到下的表。它的字段编码是有规范的,直观的就是javap 反解析出来的格式,和字节码一一对应。下面就是字节码的结构。

类型名称说明长度
u4magic魔数,识别Class文件格式4个字节
u2minor_version副版本号2个字节
u2major_version主版本号2个字节
u2constant_pool_count常量池计算器2个字节
cp_infoconstant_pool常量池n个字节
u2access_flags访问标志2个字节
u2this_class类索引2个字节
u2super_class父类索引2个字节
u2interfaces_count接口计数器2个字节
u2interfaces接口索引集合2个字节
u2fields_count字段个数2个字节
field_infofields字段集合n个字节
u2methods_count方法计数器2个字节
method_infomethods方法集合n个字节
u2attributes_count附加属性计数器2个字节
attribute_infoattributes附加属性集合n个字节

字段说明

数据类型定义说明
u*无符号整数例如u1就是一个字节
info表,复合数据通常没有固定长度,以_info结尾,通常前面都会长度length说明

1.7 常用表(速查)

1.7.1 常量类型表

基本概念

常量池主要存放两大常量:字面量literals (string, integer, and floating point constants)符号引用 Symbolic References

常量具体的常量解释
字面量文本字符串
声明为final的常量值
符号引用类和接口的全限定名形如com/sun/Demo;com/sun/Hello,把 . 换成 / ,多个用 ;隔离
字段的名称和描述符简单名称:比如add()和num()的简单名称是addnum
方法的名称和描述符描述符:

描述符表
描述符的作用是用来描述字段的数据类型、方法的参数列表(包括数量、类型以及顺序)和返回值。根据描述符规则,基本数据类型(byte、char、double、float、int、long、short、boolean)以及代表无返回值的void类型都用一个大写字符来表示,而对象类型则用字符L加对象的全限定名来表示,详见下表:

标志符含义
B基本数据类型byte
C基本数据类型char
D基本数据类型double
F基本数据类型float
I基本数据类型int
J基本数据类型long
S基本数据类型short
Z基本数据类型boolean
V基本数据类型void
L对象类型,如Ljava/lang/Object
正式表(14个)
类型标志16进制描述
CONSTANT_utf8_info11UTF-8编码的字符串
CONSTANT_Integer_info33整形字面量
CONSTANT_Float_info44浮点型字面量
CONSTANT_Long_info55长整型字面量
CONSTANT_Double_info66双精度浮点型字面量
CONSTANT_Class_info77类或接口的符号引用
CONSTANT_String_info88字符串类型字面量
CONSTANT_Fieldref_info99字段的符号引用
CONSTANT_Methodref_info10a类中方法的符号引用
CONSTANT_InterfaceMethodref_info11b接口中方法的符号引用
CONSTANT_NameAndType_info12c字段或方法的符号引用
CONSTANT_MethodHandle_info15e表示方法句柄
CONSTANT_MothodType_info1610标志方法类型
CONSTANT_InvokeDynamic_info1812表示一个动态方法调用点

详解
在这里插入图片描述

1.7.2 类访问权限控制表(修饰符)

常量池后面就是访问标志,用两个字节来表示,其标识了类或者接口的访问信息,比如:该Class文件是类还是接口,是否被定义成public,是否是abstract,如果是类,是否被声明成final等等

标志名称标志值含义
ACC_PUBLIC0x0001是否为Public类型
ACC_FINAL0x0010是否被声明为final,只有类可以设置
ACC_SUPER0x0020是否允许使用invokespecial字节码指令的新语义,JDK1
ACC_INTERFACE0x0200标志这是一个接口
ACC_ABSTRACT0x0400是否为abstract类型,对于接口或者抽象类来说,次标志值为真,其他类型为假
ACC_SYNTHETIC0x1000标志这个类并非由用户代码产生
ACC_ANNOTATION0x2000标志这是一个注解
ACC_ENUMx4000标志这是一个枚举

1.7.3(field)字段表

访问权限控制(修饰符)

publicprivateprotected)、static修饰符final修饰符volatile等等

标志名称标志值含义
ACC_PUBLIC0x0001字段是否为public
ACC_PRIVATE0x0002字段是否为private
ACC_PROTECTED0x0004字段是否为protected
ACC_STATIC0x0008字段是否为static
ACC_FINAL0x0010字段是否为final
ACC_VOLATILE0x0040字段是否为volatile
ACC_TRANSTENT0x0080字段是否为transient
ACC_SYNCHETIC0x1000字段是否为由编译器自动产生
ACC_ENUM0x4000字段是否为enum
字段表结构
类型名称含义数量
u2access_flags访问标志1
u2name_index字段名索引1
u2descriptor_index描述符索引1
u2attributes_count属性计数器1
attribute_infoattributes属性集合attributes_count

1.7.4 方法

访问权限(修饰符)
标志名称标志值含义
ACC_PUBLIC0x0001方法是否为public
ACC_PRIVATE0x0002方法是否为private
ACC_PROTECTED0x0004方法是否为protected
ACC_STATIC0x0008方法是否为static
ACC_FINAL0x0010方法是否为final
ACC_SYHCHRONRIZED0x0020方法是否为synchronized
ACC_BRIDGE0x0040方法是否是有编译器产生的方法
ACC_VARARGS0x0080方法是否接受参数
ACC_NATIVE0x0100方法是否为native
ACC_ABSTRACT0x0400方法是否为abstract
ACC_STRICTFP0x0800方法是否为strictfp
ACC_SYNTHETIC0x1000方法是否是有编译器自动产生的
方法表结构
类型名称含义数量
u2access_flags访问标志1
u2name_index方法名索引1
u2descriptor_index描述符索引1
u2attributes_count属性计数器1
attribute_infoattributes属性集合attributes_count

1.7.5 属性表

官方
一个属性表被用在ClassFile,field_infomethod_infoCode_attribute

属性表的结构
类型名称数量含义
u2attribute_name_index1属性名索引
u2attribute_length1属性长度
u1infoattribute_length属性表
jvm预定义的属性表
属性名称使用位置含义
Code方法表Java代码编译成的字节码指令
ConstantValue字段表final关键字定义的常量池
Deprecated类,方法,字段表被声明为deprecated的方法和字段
Exceptions方法表方法抛出的异常
EnclosingMethod类文件仅当一个类为局部类或者匿名类是才能拥有这个属性,这个属性用于标识这个类所在的外围方法
InnerClass类文件内部类列表
LineNumberTableCode属性Java源码的行号与字节码指令的对应关系
LocalVariableTableCode属性方法的局部变量描述
StackMapTableCode属性JDK1
Signature类,方法表,字段表用于支持泛型情况下的方法签名
SourceFile类文件记录源文件名称
SourceDebugExtension类文件用于存储额外的调试信息
Synthetic类,方法表,字段表标志方法或字段为编译器自动生成的
LocalVariableTypeTable使用特征签名代替描述符,是为了引入泛型语法之后能描述泛型参数化类型而添加
RuntimeVisibleAnnotations类,方法表,字段表为动态注解提供支持
RuntimeInvisibleAnnotations表,方法表,字段表用于指明哪些注解是运行时不可见的
RuntimeVisibleParameterAnnotation方法表作用与RuntimeVisibleAnnotations属性类似,只不过作用对象为方法
RuntimeInvisibleParameterAnnotation方法表作用与RuntimeInvisibleAnnotations属性类似,作用对象哪个为方法参数
AnnotationDefault方法表用于记录注解类元素的默认值
BootstrapMethods类文件用于保存invokeddynamic指令引用的引导方式限定符
举例 code属性表
类型名称数量含义
u2attribute_name_index1属性名索引
u4attribute_length1属性长度
u2max_stack1操作数栈深度的最大值
u2max_locals1局部变量表所需的存续空间
u4code_length1字节码指令的长度
u1codecode_length存储字节码指令
u2exception_table_length1异常表长度
exception_infoexception_tableexception_length异常表
u2attributes_count1属性集合计数器
attribute_infoattributesattributes_count属性集合
LineNumberTable属性表结构
类型名称数量含义
u2attribute_name_index1属性名索引
u4attribute_length1属性长度
u2line_number_table_length1行号表长度
line_number_infoline_number_tableline_number_table_length行号表
LocalVariableTable 属性

在这里插入图片描述

LocalVariableTable_attribute {
    u2 attribute_name_index;
    u4 attribute_length;
    u2 local_variable_table_length;
    {   u2 start_pc;
        u2 length;
        u2 name_index;
        u2 descriptor_index;
        u2 index;
    } local_variable_table[local_variable_table_length];
}
LineNumberTable属性
类型名称数量含义
u2attribute_name_index1属性名索引
u4attribute_length1属性长度
u2line_number_table_length1行号表长度
line_number_infoline_number_tableline_number_table_length行号表

二、讲解

引用

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值