class文件中,常量池、方法表、属性表,异常表等等相关数据解析!小白就跟我一起对照学【class字节码文件分析】

news2024/12/29 8:45:28

前言:前段时间读《深入java虚拟机》介绍到class文件的时候,由于理论知识较多,人总感觉疲惫不堪,就泛泛阅读了一下。在工作中使用起来知识点知道,但是总是需要查阅各种资料。今天有时间,继续整理常量池后面的相关知识。

文章目录

  • 源码
  • 编译之后的javap文件
  • 1、访问标志
  • 2、类索引、父类索引、接口索引
  • 字段表集合
    • 1、字段表结构
    • 2、字段表的访问标识
  • 方法表集合
    • 1、方法表结构
    • 2、方法表的访问标识
  • code属性表

源码

public class Sample {
    public String m1;
    public String m2;
    public Object [] arr;

    public static void main(String[] args) {
        Sample sample = new Sample();
        sample.m1="22";
        sample.arr=new Object[12];
        System.out.println(sample.m1);
    }
}

编译之后的javap文件

  Last modified 2023-6-2; size 708 bytes
  MD5 checksum fc8bb4833223a10b68449d42080b1695
  Compiled from "Sample.java"
public class com.company.jvm.Sample
  minor version: 0
  major version: 52
  flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
   #1 = Methodref          #6.#29         // java/lang/Object."<init>":()V
   #2 = Class              #30            // com/company/jvm/Sample
   #3 = Methodref          #2.#29         // com/company/jvm/Sample."<init>":()V
   #4 = String             #31            // 22
   #5 = Fieldref           #2.#32         // com/company/jvm/Sample.m1:Ljava/lang/String;
   #6 = Class              #33            // java/lang/Object
   #7 = Fieldref           #2.#34         // com/company/jvm/Sample.arr:[Ljava/lang/Object;
   #8 = Fieldref           #35.#36        // java/lang/System.out:Ljava/io/PrintStream;
   #9 = Methodref          #37.#38        // java/io/PrintStream.println:(Ljava/lang/String;)V
  #10 = Utf8               m1
  #11 = Utf8               Ljava/lang/String;
  #12 = Utf8               m2
  #13 = Utf8               arr
  #14 = Utf8               [Ljava/lang/Object;
  #15 = Utf8               <init>
  #16 = Utf8               ()V
  #17 = Utf8               Code
  #18 = Utf8               LineNumberTable
  #19 = Utf8               LocalVariableTable
  #20 = Utf8               this
  #21 = Utf8               Lcom/company/jvm/Sample;
  #22 = Utf8               main
  #23 = Utf8               ([Ljava/lang/String;)V
  #24 = Utf8               args
  #25 = Utf8               [Ljava/lang/String;
  #26 = Utf8               sample
  #27 = Utf8               SourceFile
  #28 = Utf8               Sample.java
  #29 = NameAndType        #15:#16        // "<init>":()V
  #30 = Utf8               com/company/jvm/Sample
  #31 = Utf8               22
  #32 = NameAndType        #10:#11        // m1:Ljava/lang/String;
  #33 = Utf8               java/lang/Object
  #34 = NameAndType        #13:#14        // arr:[Ljava/lang/Object;
  #35 = Class              #39            // java/lang/System
  #36 = NameAndType        #40:#41        // out:Ljava/io/PrintStream;
  #37 = Class              #42            // java/io/PrintStream
  #38 = NameAndType        #43:#44        // println:(Ljava/lang/String;)V
  #39 = Utf8               java/lang/System
  #40 = Utf8               out
  #41 = Utf8               Ljava/io/PrintStream;
  #42 = Utf8               java/io/PrintStream
  #43 = Utf8               println
  #44 = Utf8               (Ljava/lang/String;)V
{
  public java.lang.String m1;
    descriptor: Ljava/lang/String;
    flags: ACC_PUBLIC

  public java.lang.String m2;
    descriptor: Ljava/lang/String;
    flags: ACC_PUBLIC

  public java.lang.Object[] arr;
    descriptor: [Ljava/lang/Object;
    flags: ACC_PUBLIC

  public com.company.jvm.Sample();
    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/company/jvm/Sample;

  public static void main(java.lang.String[]);
    descriptor: ([Ljava/lang/String;)V
    flags: ACC_PUBLIC, ACC_STATIC
    Code:
      stack=2, locals=2, args_size=1
         0: new           #2                  // class com/company/jvm/Sample
         3: dup
         4: invokespecial #3                  // Method "<init>":()V
         7: astore_1
         8: aload_1
         9: ldc           #4                  // String 22
        11: putfield      #5                  // Field m1:Ljava/lang/String;
        14: aload_1
        15: bipush        12
        17: anewarray     #6                  // class java/lang/Object
        20: putfield      #7                  // Field arr:[Ljava/lang/Object;
        23: getstatic     #8                  // Field java/lang/System.out:Ljava/io/PrintStream;
        26: aload_1
        27: getfield      #5                  // Field m1:Ljava/lang/String;
        30: invokevirtual #9                  // Method java/io/PrintStream.println:(Ljava/lang/String;)V
        33: return
      LineNumberTable:
        line 9: 0
        line 10: 8
        line 11: 14
        line 12: 23
        line 13: 33
      LocalVariableTable:
        Start  Length  Slot  Name   Signature
            0      34     0  args   [Ljava/lang/String;
            8      26     1 sample   Lcom/company/jvm/Sample;
}
SourceFile: "Sample.java"

1、访问标志

class文件中,我们可以通过背或记也好,或者通过查阅对照表。可以将常量池中的数据整理出来。常量池的数据,之后又是什么呢?紧接着的就是访问标志

标志名称标志值标志意义
ACC_PUBLIC0X0001是否为public类型
ACC_FINAL0X0010是否被声明为final,只有类可设置
ACC_SUPER0x0020在jdk1.0.2之后编译出来的类的这个标志都为真
ACC_INTERFACE0x0200标识是一个接口
ACC_ABSTRACT0x4000是否为abstract类型,如为真,其他类型均为假,如INTERFACE
ACC_SYNTHETIC0x1000标识这个类并非由用户产生
ACC_ANNOTATION0x2000标识这是一个注解
ACC_ENUM0x4000标识这是一个枚举
ACC_MODULE0x8000标识这是一个模块

这里先上一张二进制的图:
在这里插入图片描述

下面是常量池之后的class文件截取的部分:

00 21 

访问标志,占用空间:U2,这里占用了十六进制的4个位,则是0x0021。这里我啰嗦一下,一个字节为8个位,对应到十六机制来说【两个位】代表一个字节。eg:0xF标识二进制的0000 1111,去除高位的0,就是1111。
在表格中我们说过,ACC_SUPER标志在jdk1.0.2之后的版本其值都为真,则是0x0020,说明其访问标志ACC_PUBLIC为真!0x0001|0x0020=0x0021

2、类索引、父类索引、接口索引

访问标志结束之后,就来到了我们所声明的类例,如下伪代码

public class dog extend cat implement animal{

}
00 02 00 06 00 00

__类索引、父类索引、接口索引占用的内存均为u2。

u2索引说明
00 02#2代表当前类的索引,通过查找为com/company/jvm/Sample
00 08#8代表当前父类索引,通过查找为Object
00 000代表当前文件没有接口

字段表集合

通过字面意,就能得知这里将要介绍的是类或接口成员字段

//这里写个伪代码
public final static int AGE=10;

1、字段表结构

类型名称数量说明
u2filed_count1字段数量
u2access_flag1访问标志
u2name_index1名称索引
u2descriptor_index1类型索引
u2attribute_count1属性计数器
u2attributesattribute_count属性值集合

2、字段表的访问标识

标志名称标志值含义
ACC_PUBLIC0x0001字段是否为公开
ACC_PRIVATE0x0002字段是否为私有
ACC_PROTECTED0x0004字段是否为保护
ACC_STATIC0x0008字段是否为静态
ACC_FINAL0x0010字段是否为Final
ACC_VOLATILE0x0040字段是否在并发时可见
ACC_TRANSIENT0x0080字段是否序列化
ACC_SYNTHETIC0x1000字段是否由编译器自己决定
ACC_ENUM0x4000字段是否为枚举
00 03 00 01 00 0a 00 0b  00 00 00 01 00 0c 00 0b 00 00 00 01 00 0d 00 0e 00 00 
位值说明
第一个成员字段
00 03代表字段数量有3个
00 01代表字段访问标志位public
00 0a代表名称索引为10 名称为 m1
00 0b代表descriptor的索引值为11 对象类型为Ljava/lang/String;【分号;全限定名】
00 00代表没有属性数量
第二个成员字段
00 01代表字段访问标志位为public
00 0c代表字段名称索引为12,名称为m2
00 0b代表类型的索引11,类型为 Ljava/lang/String;同上
00 00代表没有属性
第三个成员字段
00 01同上
00 0d名称索引为13,经查找为arr
00 0e类型索引为14,经查找为 [Ljava/lang/Object;全限定名,其中“[”代表为数组
00 00代表没有属性,数量为0

方法表集合

唠嗑时间开始,写到这里花了三个多小时。从排版到书写上面确实有很大的提升。此时的我确实有点疲惫。仔细一想,没啥子疲惫不疲惫的,路虽远,但始终在路上,总会到达终点。突然想到书上说过这样的一句:当你在解决一个问题的时候,你会感到很疲惫,这时候千万别放弃。因为大部分的人就此放弃了,而你还在路上行走。当你解决之后,你又比别人强了不少!

写到这里【字段表集合】之后,这里就会很轻松。这里再啰嗦一下,字段表分为:成员字段数量、字段名索引、字段类型索引、字段属性数量、字段属性集合。

1、方法表结构

类型名称数量说明
method_count方法数量
u2access_flag1访问标志
u2name_index1名称索引
u2descriptor_index1类型索引
u2attributes_count1属性数量
attributes_countattributes_[attributes_count]1属性表

2、方法表的访问标识

标志名称标志值含义
ACC_PUBLIC0x0001方法是否为公开
ACC_PRIVATE0x0002方法是否为私有
ACC_PROTECTED0x0004方法是否为保护
ACC_STATIC0x0008方法是否为静态
ACC_FINAL0x0010方法是否为Final
ACC_SYNCHRONIZED0x0020方法是否在并发时可见
ACC_BRIDGE0x0040方法是不是由编译器产生的桥接方法
ACC_VARCHAR0x0080方法是否接收不可定参数
ACC_NATIVE0x0100方法是否为Native
ACC_ABSTRACT0x0400方法是否为abstract
ACC_STRICT0x0800方法是否为strictfp【修饰在接口和类,对精确率类型较高且跨平台的计算结果要求比较严格的清醒的话,建议使用该strictfp关键词。】
ACC_SYNTHETIC0x1000方法是否由编译器自动产生

code属性表

类型名称数量
u2attribute_name_index1
u4attribute_length1
u2max_stack1
u2max_locals1
u4code_length1
u1codecode_length
u2exception_table_length1
exception_infoexception_tableexception_table_length
u2attributes_count1
attribute_infoattributesattributes_count

继续上方法表的字节码:

00 02 00 01 00 0f 00 10 00 01 00 11 00 00 00 2f 00 00 00 01 00 00 00 05 2a b7 00 01 b1 00 00

现在对照上面的说明,现在逐一说明:

对照位码说明
methods_count00 02存在2个方法
acc_flags00 01访问标识 public
name_index00 0f方法名索引为15,经查为< init >
descriptor_index00 10方法描述索引为16,经常为()v
attributes_count00 01属性只有一个
attributes_name_index00 11属性名索引为17,经查为code
attributes_length00 00 00 2f属性值长度为47
max_stack00 00最大栈深为0
max_locals00 01需要分配1个变量槽,根据同时生存的最大局部变量数和类型计算
code_length00 00 00 05字节码长度
code2a查看指令表为aload_0
codeb7同上~,invokespecial,调用超类构造方法,实例初始化方法,私有方法
code00同上~,nop,什么都不做
code01同上~,acoust_null,将null推送至栈顶
codeb1同上~,return ,从当前方法返回void
exception_table_lenght00 00当前没有发现异常信息
attributes_count00 02该方法的附加属性共有2个
attribute_name_index0012属性名索引为18,经查为 LineNumberTable
attribute_length00 00 00 06属性长度为6
line_number_table_length00 01字节码行号共1行
star_pc00 00从字节码第0行开始。此处说的行数是一种抽象的,指的是相对于方法体的偏移
line_number00 03java行号为3
attribute_name_index00 13属性名称索引为19,经查为 LocalVariableTable
attribute_length00 00 00 0c属性长度为12
local_variable_table_length00 01局部变量表长度为1
star_pc00 00局部变量的生命周期开始的字节码偏移量
length00 05往后偏移5个地址的长度,star_pc和length的配合使用就是局部变量在字节码中的作用域范围
name_index00 14名字索引为20,经查为 this
descriptor_index00 15描述索引为21,经查为Lcom/company/jvm/Sample;
index00 00这个局部变量在栈帧的局部变量表中变量槽的为之为0
acc_flag00 09public的标志0x0001,static的标志0x0008,0x0001
name_index00 16名字为索引22,经查为 main
descriptor_index00 17描述的索引为23,经查([Ljava/lang/String;)V
attributes_count00 01当前方法的属性长度为1
attribute_name_index00 11当前属性名称索引值为17,经查为Code
attribute_length00 00 00 66当前属性的长度为102
attribute_name_index00 02属性名称索引为2,经查为com/company/jvm/Sample
max_stack00 02栈帧最大深度为2
max_local00 02最大局部变量槽数为2
code_lenght00 00 00 22字节码长度为34
codebb经查字节码指令,0xbb为new
code00Nop,什么事都不做
code02同上经查,为将int型-1推送至栈顶
code590x59,经查为dump,赋值栈顶数值并压入栈顶
codeb70xb7,invokespecial,调用超类构造方法,实例化初始方法,私有方法
code00Nop 不做任何事
code030x03,将int的0推送至栈顶
code0x27e一直都这个位都是code值
exception_table_lenght00 00说明没有任何异常信息
attributes_count00 02说明有两条
同上面分析~同上面分析~同上面分析~

到最后8位为Source

标识位码说明
attribute_name_index00 1b名称索引为27,经查为SourceFile
attribute_length00 00 00 02对应值为2
sourcefile_index00 1c对应的文件索引值为28, 经查为Sample.java

至此一个简单的文件就翻译完成了,对照着javap和字节码整理之后,确实有一番收获。但是还处于道可道非常道的过程,仍然需要透彻一些!明天继续干~

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/605884.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

session与cookie

session是一种会话机制。当客户端发送登录请求时&#xff0c;服务端会生成一个sessionId存储在cookie中返回给客户端&#xff0c;客户端通过响应数据中的set-cookie字段来获取cookie并保存。如果客户端再向同一网站发送请求时&#xff0c;会自动携带cookie&#xff0c;相当于一…

离散数学_十章-图 ( 5 ):连通性 - 下

&#x1f4f7;10.5 图的连通性 4. 有向图的连通性4.1 强连通4.2 弱连通4.3 &#xff08;有向图的&#xff09;强连通分支 5. 通路与同构6. 顶点间通路个数的计算 4. 有向图的连通性 根据是否考虑边的方向&#xff0c;在有向图中有两种连通性概念&#xff1a; 4.1 强连通 强连…

C/C++线程绑核详解

在一些大型的工程或者特殊场景中&#xff0c;我们会听到绑核&#xff0c;绑核分为进程绑核和线程绑核。绑核的最终目的都是为了提高程序和性能或者可靠性。 一&#xff1a;为什么需要绑核 操作系统发展至今&#xff0c;已经能很好的平衡运行在操作系统上层的应用&#xff0c;兼…

16.3:岛屿数量问题2

岛屿数量问题2 https://leetcode.cn/problems/number-of-islands-ii/ 给你一个大小为 m x n 的二进制网格 grid 。网格表示一个地图&#xff0c;其中&#xff0c;0 表示水&#xff0c;1 表示陆地。最初&#xff0c;grid 中的所有单元格都是水单元格&#xff08;即&#xff0c…

Dubbo源码解析一网络通信原理

Dubbo 网络通信原理 1. Dubbo高可用集群1.1 服务集群的概述1.1.1 服务集群的概述1.1.2 调用过程1.1.3 组件介绍 1.2 集群容错机制1.2.1 内置集群容错策略1.2.1.1 Failover(失败自动切换)1.2.1.2 Failsafe(失败安全)1.2.1.3 Failfast(快速失败)1.2.1.4 Failback(失败自动恢复)1.…

卡尔曼滤波 | Matlab实现利用卡尔曼滤波器估计电池充电状态(Kalman Filtering)

文章目录 效果一览文章概述研究内容程序设计参考资料效果一览 文章概述 卡尔曼滤波 | Matlab实现利用卡尔曼滤波器估计电池充电状态(Kalman Filtering) 研究内容

gyp verb `which` failed Error: not found: python2

安装node-sass居然需要python2,7环境&#xff0c;不能python3 我只能重新降版本&#xff1a; python2.7:https://www.python.org/ftp/python/2.7/python-2.7.amd64.msi npm ERR! code 1 npm ERR! path F:\idea2021work\music01 初始化\music-client\node_modules\node-sass np…

自然语言处理从入门到应用——自然语言处理的基础任务:词性标注(POS Tagging)和句法分析(Syntactic Parsing)

分类目录&#xff1a;《自然语言处理从入门到应用》总目录 词性标注 词性是词语在句子中扮演的语法角色&#xff0c;也被称为词类&#xff08;Part-Of-Speech&#xff0c;POS&#xff09;。例如&#xff0c;表示抽象或具体事物名字&#xff08;如“计算机”&#xff09;的词被…

【遗传算法简介】

遗传算法&#xff1a;原理与实战 简介 遗传算法是一种模拟达尔文生物进化论的自然选择以及遗传学机制的搜索算法&#xff0c;由 John Holland 在20世纪70年代提出。它们在各种搜索、优化和机器学习任务中已被广泛应用。 遗传算法原理 1. 编码 遗传算法的第一步是将问题的可…

Andriod开发 Room 数据库处理框架

1.Room框架 Room是Android Jetpack组件库中的一部分&#xff0c;它是一个SQLite数据库的抽象层&#xff0c;提供了更简单的API和更好的性能&#xff0c;适合于中大型应用程序。 2.Room的使用 使用Room和之前使用SQLite搭建数据库的过程类似&#xff0c;但是更加简单了。 1&…

JAVA网络编程(一)

一、什么是网络编程 定义&#xff1a;在网络通信协议下&#xff0c;不同计算机上运行的程序&#xff0c;进行的数据传输。 应用场景&#xff1a;即时通信&#xff0c;网游&#xff0c;邮件等 不管什么场景&#xff0c;都是计算机与计算机之间通过网络在进行数据传输 java提供一…

软件测试必会:cookie、session和token的区别

今天就来说说session、cookie、token这三者之间的关系&#xff01;最近这仨玩意搞得头有点大&#x1f923; 01、为什么会有它们三个 我们都知道 HTTP 协议是无状态的&#xff0c;所谓的无状态就是客户端每次想要与服务端通信&#xff0c;都必须重新与服务端链接&#xff0c;意…

穿针引线之 AsyncLocalStorage

在 Node.js 中&#xff0c;如何更优雅地获取请求上下文一直是一个问题&#xff0c;看一下下面的例子。 背景 const http require(http); function handler1(req, res) {console.log(req.url); }function handler2(req, res) {console.log(req.url); }http.createServer((req…

【react全家桶】react-Hook (下)

本人大二学生一枚&#xff0c;热爱前端&#xff0c;欢迎来交流学习哦&#xff0c;一起来学习吧。 <专栏推荐> &#x1f525;&#xff1a;js专栏 &#x1f525;&#xff1a;vue专栏 &#x1f525;&#xff1a;react专栏 文章目录 15【react-Hook &#xff08;下&#x…

进程控制(Linux)

进程控制 fork 在Linux中&#xff0c;fork函数是非常重要的函数&#xff0c;它从已存在进程中创建一个新进程。新进程为子进程&#xff0c;而原进程为父进程。 返回值&#xff1a; 在子进程中返回0&#xff0c;父进程中返回子进程的PID&#xff0c;子进程创建失败返回-1。 …

Spring - BeanFactory与ApplicationContext介绍

文章目录 Spring Bean一、BeanFactory 快速入门1.1 BeanFactory 开发步骤1.2 DI依赖注入 二、ApplicationContext快速入门2.1 入门2.2 BeanFactory 与 ApplicationContext关系2.3 BeanFactory 继承体系2.4 ApplicationContext 继承体系 Spring Bean 之前也了解过Spring Bean&a…

高斯过程回归 | Matlab实现高斯过程回归多输入单输出预测(Gaussian Process Regression)

文章目录 效果一览文章概述研究内容程序设计参考资料效果一览 文章概述 高斯过程回归 | Matlab实现高斯过程回归多输入单输出预测(Gaussian Process Regression) 研究内容 高斯过程回归(Gaussian Process Regression,GPR)是一种基于概率模型的非参数回归方法,可以用于

mybatisplus数据权限插件学习初探 动态表名更换插件

文章目录 学习链接 mybatisplus数据权限插件学习初探前言案例建表用户表订单表 环境准备UserUserMapperUserMapper.xmlOrdersOrdersMapperOrdersMapper.xml 配置UserTypeEnumUserContextHolderCustomizeDataPermissionHandlerMybatisPlusConfig 测试测试类bossdeptManagerclerk…

Zinx框架学习 - 消息封装

Zinx - V0.5 消息封装 之前我们使用Request来保存服务器的数据&#xff0c;很显然使用[]byte来接收数据&#xff0c;没有长度也没有消息类型&#xff0c;接下来就要针对这个消息进行封装 创建消息类型 定义一个基本的message包&#xff0c;会包含消息ID、数据、数据长度三个…

路径规划算法:基于探路者优化的路径规划算法- 附代码

路径规划算法&#xff1a;基于探路者优化的路径规划算法- 附代码 文章目录 路径规划算法&#xff1a;基于探路者优化的路径规划算法- 附代码1.算法原理1.1 环境设定1.2 约束条件1.3 适应度函数 2.算法结果3.MATLAB代码4.参考文献 摘要&#xff1a;本文主要介绍利用智能优化算法…