Java字节码常量池深度剖析与字节码整体结构分解
常量池深度剖析:
在上一次【https://www.cnblogs.com/webor2006/p/9416831.html】中已经将常量池分析到了2/3了,接着把剩下的分析完,先回顾一下我们编译的源文件为:

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

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

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

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

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

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

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

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

接下来继续读一个字节:

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

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

看一下javap -verbose:

实际上"getA()I"就可以确认其方法名为getA,无参,并且返回值为整型,就可以完全的对应的源程序中的方法了。
接下来继续往下,读一个字节:

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

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

对一下javap -verbose:

继续往下,读一个字节:

再数2个字节:

往下数四个字节:

对应于javap -verbose:

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


往下数10个字节:

对应javap -verbose:

代表源文件,再往下读:


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

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

继续往下走:

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

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

看一下javap -verbose所显示的:

其中方法名称为<init>表示是构造方法,而()V表示该构造方法不带参数没的返回值,也就是默认构造方法。
接下来继续:

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

对应javap -verbose:

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

继续往下看:

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

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

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

再往下数两个字节:

16,则往下数16个字节:

对应javap -verbose:

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

为24个,但是由于第一个为备用的,所以总常量池的大小为23,而每个常量第一个字节都是什么类型的常量,然后不同的常量其往下读几个字节都是确定的,所以这样就可以知道读到哪常量池就结束了。
字节码整体结构分解:
上面已经将整个常量池都已经分析完了,那之后还有那么多字节:

对应javap -verbose:
Classfile /Users/xiongwei/Documents/workspace/IntelliJSpace/jvm_lectue/out/production/classes/com/jvm/bytecode/MyTest1.class
Last modified Aug 10, 2018; size 479 bytes
MD5 checksum 4616561f95c24d6b04ea48a360437b8d
Compiled from "MyTest1.java"
public class com.jvm.bytecode.MyTest1
minor version: 0
major version: 52
flags: ACC_PUBLIC, ACC_SUPER
Constant pool:
#1 = Methodref #4.#20 // java/lang/Object."<init>":()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 <init>
#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 // "<init>":()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."<init>":()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"
目前还分析不了,因为还缺少知识理论,所以先来补一补知识,先来对字节码的整体结构有一个了解,先来看张图:

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

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

如:public、public static、public abstract、private、protected等。
接着往下表示当前类的名字,如下:

再往下表示父类的名字:

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

其中可以发现一个细节:

父类的字节数是确定的,而接口是不确实的,这也跟java的单继承多实现的特性吻和。
继续往下则是字段相关的信息:

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

这个就比较复杂了,因为方法里面有执行代码,在未来会学习到。
最后则表示当前类的一些附加的属性:

因为JVM在编译时会增加一些特定的一些属性信息。
Java字节码常量池深度剖析与字节码整体结构分解的更多相关文章
- Java字节码常量池深入剖析
继续来分析Java字节码,上一节分析了魔数的规则,接下来继续往下分析,其上次总结的规则也一起贴出来: 1.使用javap -verbose命令分析一个字节码文件时,将会分析该字节码文件的魔数.版本号. ...
- Java之线程池深度剖析
1.线程池的引入 引入的好处: 1)提升性能.创建和消耗对象费时费CPU资源 2)防止内存过度消耗.控制活动线程的数量,防止并发线程过多. 使用条件: 假设在一台服务器完成一 ...
- Android之线程池深度剖析
1.线程池的引入 引入的好处: 1)提升性能.创建和消耗对象费时费CPU资源 2)防止内存过度消耗.控制活动线程的数量,防止并发线程过多. 使用条件: 假设在一台服务器完成一 ...
- class字节码结构(一)(字节码结构和字节常量池的结构)
<Java虚拟机原理图解> 1.1.class文件基本组织结构 关于变量的几个叫法: 局部变量/全局变量:很好区分根据所在位置. 类变量:静态的全局变量. 类常量:全局的final修饰的变 ...
- 你所不知道的库存超限做法 服务器一般达到多少qps比较好[转] JAVA格物致知基础篇:你所不知道的返回码 深入了解EntityFramework Core 2.1延迟加载(Lazy Loading) EntityFramework 6.x和EntityFramework Core关系映射中导航属性必须是public? 藏在正则表达式里的陷阱 两道面试题,带你解析Java类加载机制
你所不知道的库存超限做法 在互联网企业中,限购的做法,多种多样,有的别出心裁,有的因循守旧,但是种种做法皆想达到的目的,无外乎几种,商品卖的完,系统抗的住,库存不超限.虽然短短数语,却有着说不完,道不 ...
- Java 语言中一个字符占几个字节?
Java中理论说是一个字符(汉字 字母)占用两个字节. 但是在UTF-8的时候 new String("字").getBytes().length 返回的是3 表示3个字节 作者: ...
- Java编译时常量和运行时常量
Java编译时常量和运行时常量 编译期常量指的就是程序在编译时就能确定这个常量的具体值. 非编译期常量就是程序在运行时才能确定常量的值,因此也称为运行时常量. 在Java中,编译期常量指的是用fina ...
- Java中的常量池
JVM中有: Class文件常量池.运行时常量池.全局字符串常量池.基本类型包装类对象 常量池 Class文件常量池: class文件是一组以字节为单位的二进制数据流,在java代码的编译期间,编写的 ...
- 深入剖析 RocketMQ 源码 - 消息存储模块
一.简介 RocketMQ 是阿里巴巴开源的分布式消息中间件,它借鉴了 Kafka 实现,支持消息订阅与发布.顺序消息.事务消息.定时消息.消息回溯.死信队列等功能.RocketMQ 架构上主要分为四 ...
随机推荐
- SQL 删除数据库
SQL DROP DATABASE 语句 是一条DDL SQL语句.DROP DATABASE语句用于删除数据库.删除数据库将删除其中的所有数据库对象(表,视图,过程等).用户应具有删除数据库的管理员 ...
- bzoj3624(Apio2008):免费道路
题目↓ Sample Input 5 7 2 1 3 0 4 5 1 3 2 0 5 3 1 4 3 0 1 2 1 4 2 1 Sample Output 3 2 0 4 3 0 5 3 1 1 2 ...
- 日常工作问题解决:centos7下配置网卡以及查询网卡UUID
目录 1.配置网卡 1.1 网卡查看命令:ifconfig -a 1.2 网卡配置文件说明 1.3 重启网络服务 2.查看确认网卡UUID 2.1 网卡配置文件正常时 2.2 网卡配置文件不可用或者配 ...
- Xamarin.Forms FlyoutIcon 不显示(not shown)
升级了VS2019到16.4版本,然后默认创建了一个Xamarin Shell程序 结果运行后是这个样子 难道不应该是这个样子吗? 百了个度一晚上没解决,资料本身就少,再就是提示设置FlyoutIco ...
- 还是a+b
题目描述: 给定 2 个正整数 a, b,a 和 b 最多可能有 40 位,求出 a + b 的和.输入描述: 两个正整数 a, b,a 和 b 最多可能有 40 位.一行表示一个数.输出描述: a ...
- Excel逻辑运算函数
Excel逻辑运算函数 1.FALSE和TRUE的使用 筛选出表中salary>6.gender为男.age>28至少满足这三个条件中的两个的数据 1.依次使用:=C2>6.=D ...
- 利用Python进行数据分析_Pandas_处理缺失数据
申明:本系列文章是自己在学习<利用Python进行数据分析>这本书的过程中,为了方便后期自己巩固知识而整理. 1 读取excel数据 import pandas as pd import ...
- Python习题006
作业一:打印10*10 星星 ★☆ 要求一:普通打印★ l = 0 while l <10: h = 0 while h < 9: print("★", end=&q ...
- spring cloud微服务实践四
spring cloud的hystrix还有一个配搭的库hystrix-dashboard,它是hystrix的一款监控工具,能直观的显示hystrix响应信息,请求成功率等.但是hystrix-da ...
- 使用Duilib开发Windows软件(4)——消息传递
云信Duilib中没有窗体类的函数可以用来直接收取到所有控件的事件,每个控件都可以单独设置自己的事件处理函数,一般在InitWindow方法中初始化各个控件的事件处理函数. 每个控件都有许多形如Att ...