当前位置: 首页 > news >正文

java字节码常量池_Java字节码常量池深度剖析与字节码整体结构分解

常量池深度剖析:

649adec1c770f66174358c61e80824ef.png

然后用javap -verbose查看一下编译字节码的信息,其中字符串相关的如下:

ba310007aee6619e47d1eb3865822274.png

而对应用Hex Fiend来查看字符码的二进制文件的位置如下:

d499e40d9e7d4e3ce3eef2cd8a05a255.png

另外在继续分析之前再来回顾下常量的对应表,如下:

dbe523452f1bc4c45f3d1b4173414dff.png

好下面开始,先来读一个字节来看一下是什么类型的常量:

ec6b8e10bfcbacd7091888baa6d96af1.png

查表可以看到是属于这个常量:

ceaf8d6a007cfac4cb6e241d3a6bd3c2.png

接着2个字节表示字符串的长度,所以往下数二个字节:

16459480dac3cf2f98f7f9af9a461b23.png

长度为4,则下往下数4个字节则为常量的内容:

57c03af9fd50e742e480fe5a6e37bde7.png

用javap -verbose来确认一下是否也是它:

51c8d8b166f59f65d86b238e41a7ac60.png

接下来继续读一个字节:

9a338401551c236b786322005a47364e.png

又是同样的常量类型,所以直接再读二个字节来看一下字符串的长度是多少:

4b1789c464bc2987a8a716dd46de9f8e.png

长度为3,则往后再数3个字节:

06165c65b8471660d0c149eabb7f25d3.png

看一下javap -verbose:

286cb37c3d0f000f64580e494030c5f0.png

实际上"getA()I"就可以确认其方法名为getA,无参,并且返回值为整型,就可以完全的对应的源程序中的方法了。

接下来继续往下,读一个字节:

c4e11e5ed361df10d9f19ffab4405619.png

同样的类型,不多说,直接往下再看两个字节来决定字符串的长度:

6821a1195508f1651d5ec26730ef4c8b.png

占四个字节,于是乎往后再数四个字节:

99b073f9b802daa9fbb9b3d457e60978.png

对一下javap -verbose:

8ffa16d46d4876eb8a4fcf816ab92e07.png

继续往下,读一个字节:

b8d5c9b53089a31375a47f6ea987c63f.png

再数2个字节:

5424e1b6bc4febe6d2517d4f87139239.png

往下数四个字节:

a1d47702d5e817eab82dfb292f6e4697.png

对应于javap -verbose:

6b2a2a869f4d7dfdf1c3bdd1fb2db366.png

而同样的“setA(I)V”,表示方法名为setA,方法的参数为整型,无返回值,这样又可以定位到具体的唯一的方法了。

继续往下:

fafde0e5a988ce8dc6d2bedc5b0b281e.png

83c5e43cf2cf4d57c80bbef3ff33536a.png

往下数10个字节:

7bee86b6ce25598b17c8bf5a48b0d3e5.png

对应javap -verbose:

07b14a83fff7df3c3bb9f4cd3472c7ad.png

代表源文件,再往下读:

934cc6aada11beb2c19b20a0f7c7643c.png

2892e6a2a512f1ab5b5f009e0e0df738.png

长度为12,往下数12个字节:

8a12ead1d4e7625783702259b9d7d1a7.png

而这两个信息描述了当前字节码文件是由哪个源文件编译出来的,所以这也是为啥在执行javap命令时有如下一个信息:

eb40792ee6735c0df99b2531e8d21857.png

继续往下走:

4bb30b809e5c1e30dcc952d647dc7df3.png

此时不再是01类型的常量了,而是12,所以具体它代表什么类型还得查表,如下:

af15d3c8e033ec938df15a367b249b9d.png

其第二项表示名称的索引,而第三项为描述的索引,所以往下读4个字节:

cabd1fdb74c2feb238800ba154e6a36d.png

看一下javap -verbose所显示的:

44a8edc2faa203933488461cf67f2a1c.png

其中方法名称为表示是构造方法,而()V表示该构造方法不带参数没的返回值,也就是默认构造方法。

接下来继续:

75e0dd2862e018a6193aa267739fe4c6.png

又是同样的常量,所以直接往后数四个字节:

2bf1f9ec49a453fbfe0fdc08b9f75eea.png

对应javap -verbose:

b28990cb98ba71104d95c1689f078528.png

这个信息表示成员变量a,如下:

cc45d024d377c2852a9572740779bf28.png

继续往下看:

8fc9c7b08d68c5cfd29dfb1a64d80d0d.png

字符串常量,对它的分析已经了如指掌了,往后数两个字节来看下字符串的长度:

60c8ceb78dbb80dc960b81bd952741ec.png

长度为24,则往后数24个字节:

d58b89c2906641f9788b7945372e1d60.png

对应javap -verbose:

d13017c63fdb9e943310f011b63bfdff.png

表示类的全局限定名,注意反应到字节码文件来说全局限定名都是以“/”分隔的,而不像我们看到的包名那样以“.”分隔的,继续往下:

9acc713ef6e52915418a2ce021053494.png

再往下数两个字节:

ce24f527985ac27929dd5b5b0e714c9b.png

16,则往下数16个字节:

5999cc35ce1c12bd8c2e15562202aae1.png

对应javap -verbose:

15c16ac98478286e2966850ae3f56b99.png

表示当前类的父类的完全限制名,到此,常量池就全部分析完了~所以总结一下,对于一个类常量池的大小是不定的,那JVM如何在字体码文件中来知道常量池在哪结束呢?首先字符码能知道常量池的总大小,如下:

eaca2141add7ab3c1a4bf0d805662225.png

为24个,但是由于第一个为备用的,所以总常量池的大小为23,而每个常量第一个字节都是什么类型的常量,然后不同的常量其往下读几个字节都是确定的,所以这样就可以知道读到哪常量池就结束了。

字节码整体结构分解:

上面已经将整个常量池都已经分析完了,那之后还有那么多字节:

bcb40c79f2799037efb85e60acf3d1e1.png

对应javap -verbose:

Classfile /Users/xiongwei/Documents/workspace/IntelliJSpace/jvm_lectue/out/production/classes/com/jvm/bytecode/MyTest1.classLast modified Aug10, 2018; size 479bytes

MD5 checksum 4616561f95c24d6b04ea48a360437b8d

Compiled from"MyTest1.java"

public classcom.jvm.bytecode.MyTest1

minor version:0major version:52flags: ACC_PUBLIC, ACC_SUPER

Constant pool:

#1 = Methodref #4.#20 //java/lang/Object."":()V

#2 = Fieldref #3.#21 //com/jvm/bytecode/MyTest1.a:I

#3 = Class #22 //com/jvm/bytecode/MyTest1

#4 = Class #23 //java/lang/Object

#5 =Utf8 a

#6 =Utf8 I

#7 = Utf8 #8 =Utf8 ()V

#9 =Utf8 Code

#10 =Utf8 LineNumberTable

#11 =Utf8 LocalVariableTable

#12 = Utf8 this#13 = Utf8 Lcom/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 //"":()V

#21 = NameAndType #5:#6 //a:I

#22 = Utf8 com/jvm/bytecode/MyTest1

#23 = Utf8 java/lang/Object

{public com.jvm.bytecode.MyTest1();

descriptor: ()V

flags: ACC_PUBLIC

Code:

stack=2, locals=1, args_size=1

0: aload_0

1: invokespecial #1 // Method java/lang/Object."":()V

4: aload_0

5: iconst_1

6: putfield #2 // Field a:I

9: return

LineNumberTable:

line 3: 0

line 4: 4

LocalVariableTable:

Start Length Slot Name Signature

0 10 0 this Lcom/jvm/bytecode/MyTest1;

public int getA();

descriptor: ()I

flags: ACC_PUBLIC

Code:

stack=1, locals=1, args_size=1

0: aload_0

1: getfield #2 // Field a:I

4: ireturn

LineNumberTable:

line 7: 0

LocalVariableTable:

Start Length Slot Name Signature

0 5 0 this Lcom/jvm/bytecode/MyTest1;

public void setA(int);

descriptor: (I)V

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 11: 0

line 12: 5

LocalVariableTable:

Start Length Slot Name Signature

0 6 0 this Lcom/jvm/bytecode/MyTest1;

0 6 1 a I

}

SourceFile: "MyTest1.java"

目前还分析不了,因为还缺少知识理论,所以先来补一补知识,先来对字节码的整体结构有一个了解,先来看张图:

5b24d3b001f31ad52fce4f2638afdc51.png

目前已经学习了前三个结构,如下:

069e3fa2f762b1360a008ab05f5d6f83.png

接着来了解新的字节结构,接下来是“Access Flags”,表示访问修饰符:

b1348faf750ce0386ae490d8aa9aea3d.png

如:public、public static、public abstract、private、protected等。

接着往下表示当前类的名字,如下:

38b977a68fb0b79f16fb614a9b60bed6.png

再往下表示父类的名字:

d906b472cdf3aa783e7b6d975461231b.png

接下来表示接口相关的信息:

f505deed33c6fb459d59d36d37a2aaef.png

其中可以发现一个细节:

f2e3bcc96d73faecf23670bebdd1d0a6.png

父类的字节数是确定的,而接口是不确实的,这也跟java的单继承多实现的特性吻和。

继续往下则是字段相关的信息:

dc9139ae5f15b2f5aee44994a296f6d2.png

接下来由是类的方法相关的一些信息:

acf15a31d7fb88e16953bee56e4f6cd2.png

这个就比较复杂了,因为方法里面有执行代码,在未来会学习到。

最后则表示当前类的一些附加的属性:

8744146cdc8128815bd52b46f5c3ded3.png

因为JVM在编译时会增加一些特定的一些属性信息。

相关文章:

  • java控制语句案例_Java基础之流程控制(示例代码)
  • mysql 怎么设置ip地址_Mysql如何设置用户指定ip地址操作数据库
  • android_iphone和java三个平台一致的加密方法_Android、iPhone和Java三个平台一致的加密工具...
  • java最崇拜谁_蓝桥杯(java)个人赛真题:小朋友崇拜圈
  • java数组函数结局实际问题_java函数与数组
  • java登录字符串封装_JAVA的随机的字符串的封装(基本上够用了)
  • java统一管理文字_为了统一管理组件和容器,Java为所有组件类定义的超类
  • django mysql 分表_Django数据库分表
  • php aws_Amazon S3 客户端加密与 AWS SDK for PHP 版本 3 - 适用于 PHP 的 AWS 开发工具包...
  • Php公钥加密data是空,实用的PHP带公钥加密类分享(每次加密结果都不一样哦)
  • java做节奏大师,《节奏大师》高手必修之路 亲测攻略_iOS游戏频道_97973手游网
  • 注册php tp5,thinkphp5 开发会员注册与登录功能
  • php xml序列化,深入理解:XML与对象的序列化与反序列化
  • matlab ceil,Matlab中的取整函数fix, floor, ceil与round
  • php 创建mssql 表,在php表中显示MSSQL选择数据
  • 0基础学习移动端适配
  • es6
  • JS基础篇--通过JS生成由字母与数字组合的随机字符串
  • Object.assign方法不能实现深复制
  • PAT A1017 优先队列
  • vue-cli3搭建项目
  • 从重复到重用
  • 腾讯大梁:DevOps最后一棒,有效构建海量运营的持续反馈能力
  • 自定义函数
  • Spark2.4.0源码分析之WorldCount 默认shuffling并行度为200(九) ...
  • ​草莓熊python turtle绘图代码(玫瑰花版)附源代码
  • ​马来语翻译中文去哪比较好?
  • #laravel 通过手动安装依赖PHPExcel#
  • (3)Dubbo启动时qos-server can not bind localhost22222错误解决
  • (vue)页面文件上传获取:action地址
  • (附源码)springboot社区居家养老互助服务管理平台 毕业设计 062027
  • (十五)devops持续集成开发——jenkins流水线构建策略配置及触发器的使用
  • (算法设计与分析)第一章算法概述-习题
  • (原+转)Ubuntu16.04软件中心闪退及wifi消失
  • (转)Android学习笔记 --- android任务栈和启动模式
  • (转)Android学习系列(31)--App自动化之使用Ant编译项目多渠道打包
  • (转)winform之ListView
  • *** 2003
  • .aanva
  • .bat批处理(七):PC端从手机内复制文件到本地
  • .Net 6.0 处理跨域的方式
  • .net core 6 集成和使用 mongodb
  • .net core Swagger 过滤部分Api
  • /dev/sda2 is mounted; will not make a filesystem here!
  • @Documented注解的作用
  • @media screen 针对不同移动设备
  • [BUUCTF NewStarCTF 2023 公开赛道] week3 crypto/pwn
  • [BZOJ 4129]Haruna’s Breakfast(树上带修改莫队)
  • [C/C++随笔] char与unsigned char区别
  • [Django ]Django 的数据库操作
  • [docker]docker网络-直接路由模式
  • [EFI]Dell Inspiron 15 5567 电脑 Hackintosh 黑苹果efi引导文件
  • [ES-5.6.12] x-pack ssl
  • [Foreman]解决Unable to find internal system admin account
  • [G-CS-MR.PS02] 機巧之形2: Ruler Circle