【世界时快讯】JVM系列:几张图看懂Java字节码
作为一个java程序员,如果你不懂字节码的话,你只能算是初级程序员了。
这可不是耸人听闻。了解字节码你才能真正了解包括“动态代理的原理”、“类加载的细节过程”、“重载和重写是如何实现的”、“多态是如何实现的”、“泛型究竟是什么”等等。
了解这些对你的工作有实际的意义:
(资料图片仅供参考)
比如,开发时碰到问题,需要确定一个jar包是不是最新的(开发时我们经常使用一个SNAPSHOT版本反复打包)。
比如,你在工具组,要开发一个动态修改运行中的类的工具。
比如,你碰到大厂高阶一些的面试,尤其是偏底层的团队。
比如,你碰到各种诡异的包括类找不到、方法找不到、java版本错误无法解析类等问题。
了解字节码就仿佛给了你另一双眼睛和更高纬度的视角,来应对各种java相关的工作。
话不多说,我们这就开始。
1、Java代码从编写到运行图片
如图所示,我们写好的java代码会先编译成字节码,然后JVM会加载这些字节码并执行其中的命令,也就是将字节码翻译为机器码执行。
这里有两个重点:
1)其他语言写的代码,如果可以翻译成标准的java字节码,一样可以在JVM中运行、事实上,有一些语言已经可以这么做了(包括Groovy、JRuby、Scala、Clojure、Kotlin等)。这是字节码技术面向未来的最大卖点,也是JVM的宏大愿景。
2)如果我们改变了编译出来字节码,其实就改变了逻辑。不需要去改原来的java代码。
2、字节码怎么看下面我们用一个例子来看看字节码到底是什么,长啥样。
public class Calculator { private static final int offset = 100; public int add(int x, int y) { int z = x + y; int m = z - offset; return m; }}
这段逻辑很简单。我定义了一个Calculator类,它有一个add方法,就是传入两个数值参数,把他们相加后再减去一个固定值offset,然后返回。
我们使用javac命令编译后,得到如下文件(十六进制):
图片
这个class人肉读起来非常费劲。他有其固定的格式,你需要按照“说明书”一个字节一个字节翻译过来才行。
这里我不做详细的介绍,看了下图你基本上就能大致了解了。
图片
一般我们看编译后的文件,绝对不会直接看十六进制的。而是使用javap命令,将其转化为我们更容易看懂的格式。我们来执行下命令:
javap -verbose Calculator.class
得到如下这样的内容:
图片
不要着急,我来逐块分开和你讲讲。
3、字节码的含义我们将字节码的内容分为三块来讲:类信息、常量池和方法表。
1)类信息这里面的内容不多,也比较容易理解。
major version: 52说明这是一个使用java8编译出来的class。
flags:ACC_PUBLIC表示这个class是public的。ACC_SUPER在JDK1.2以后编译出来的类都会带上这个标志,这和JDK1.2以后invokespecial指令的变化有关。
2)常量池常量池中保存着非常丰富的信息。包括:方法的符号引用、类的符号引用、字段或方法描述符、各种字符常量、各种基础类型字面量等等。你可以简单理解为各种你定义的类名称、属性名称、方法名称、常量以及系统自身需要的一些字面量,都会在这里定义。
下图是Calculator类的常量池数据,我做了一些标注,方便你的理解。
图片
常量池的第一列是“常量类型”,一共有十几种。每一种决定了第二列的数据格式。我这里就不详细贴图了。
常量池的第二列会有其他一些常量信息的引用,这些引用往往还是嵌套的。不过如图所示,每个复杂的常量后都有注解帮你拼接好了。
3)方法表在Calculator类中,有两个方法。其中一个是我们定义的add方法,另一个则是默认构造函数。
【方法1 - 构造函数】
我们先来看下默认构造函数。和上面一样,我直接在图中做了说明,方便理解:
图片
【方法2 - add函数】
在介绍add方法前,我们要先简单介绍下JVM的执行引擎。
JVM的执行引擎称之为“基于栈的执行引擎”。也就是说,所有计算的中间结果都存在一个专门的栈中。与之相对应的就是历史更悠久的经典“基于寄存器的操作引擎”。
我们用一个 x + y * z 的例子,来看下两种操作引擎的差别。见下图
图片
可以看到,完全一样的代码,寄存器的每个指令都需要多个参数,而基于栈的操作指令只需要一条。这是因为寄存器需要指定数据从哪个寄存器中拿(cpu有十多个寄存器),但基于栈的操作指令只会涉及一个操作数栈,所以只需要声明出栈或者入栈即可。
下面就是 x + y * z 这条命令对应的字节码操作过程:
图片
介绍完这个后,我们就可以看下Calculator类中add方法的字节码内容了:
图片
到这里,我们就把字节码中主要的三块内容都讲完了。
4、字节码实践:直接修改字节码既然我们了解了字节码的结构,我们就要实践一下直接定位并修改字节码,不然的话只是纸上功夫了。
我们写了个main函数来调用上面的Calculator类,这里把Main和Calculator类都贴一下:
public class Main { public static void main(String[] args) { System.out.println(new Calculator().add(1, 2)); }}
public class Calculator { private static final int offset = 100; public int add(int x, int y) { int z = x + y; int m = z - offset; return m; }}
我们编译并运行一下,得到如下结果:
$ javac com/codingbetterlife/justmylab/utils/*.java$ java -cp . com.codingbetterlife.justmylab.utils.Main-97
结果为 1 + 2 - 100 = -97
下面我来把add方法中的第7行通过字节码改成 int m = z + offset。
图片
修改后的class我们通过javap反编译后能看到,命令已经从isub变成了iadd。我们来运行下看看结果:
$ java -cp . com.codingbetterlife.justmylab.utils.Main103
这次变成了 1 + 2 + 100 = 103。可以看到,我们并没有重新编译,所以你只要找对地方修改正确,就可以直接改变代码逻辑了。
5、结尾当然,我并不鼓励你去修改线上的class。你也看到了,十六进制的代码是非常容易改错的。上面这个例子更多的是帮你理解java的字节码。
看了上面的内容,我不知道你是否联想到了Spring中的AOP。事实上Cglib就是通过直接修改字节码的方式来实现切面的。这点我相信你准备面试的时候肯定已经知道了,但是通过上面的内容,我相信你肯定有更深的理解了。
但事实上,更重要的话题是,要如何方便地修改字节码(不直接修改十六进制文件),这是我们下面一篇JVM系列文章会给大家介绍的内容。
此外,这些都只是编译过程中“耍的小花招”,如何重载一个运行时的类是更有意思的话题。虽然现在很多热部署方案存在各种各样的问题,从而大家都还是信赖静态编译后重新部署,但是了解对运行时类的修改和重载,是极有意义的,尤其是开发过程中。
本文转载自微信公众号「CodingBetterLife」,作者「赵志强」,可以通过以下二维码关注。
转载本文请联系「CodingBetterLife」公众号。
标签:
精彩推送
TOPBRAND | Green Sheep获融资;太古出售美国可口可乐;达利拟退市;《喜剧之王》联名喜茶;Vans推出高端副线
-最新融资-DTC母婴品牌GreenSheep获100万英镑融资近日,DTC母婴品牌Gre
新闻快讯
X 关闭
精品推荐
X 关闭
新闻快讯
- 帕金森病的症状只有“抖”吗?
- 【世界时快讯】JVM系列:几张图看懂Java字节码
- 播报:守牢案件质量生命线记全国纪检监察系统先进集体新疆维吾尔自治区纪委监委案件审理室
- 环球通讯!2023软科中国高职院校排名发布 陕西这所高校位列理工类全国第1
- 直通车数据采集_淘数据直通车选词
- 2023年7月3日氯苯价格最新行情预测
- 当前观察:教育部留学服务中心官网_教育部留学服务中心地址
- 斗罗大陆比较弱的武魂有哪些 除了神级武魂之外 当前速递
- 实时:我行我素的意思褒义还是贬义_我行我素的意思-环球简讯
- 【新要闻】苏丹首都圈大部分医院停止服务 民众缺医少药
- 新疆铁路双口岸通行中欧(中亚)班列突破7000列 当前播报
- 噩梦结束!意媒:莱奥与葡体的法律纠纷结束,被判定已还清债务-环球热消息
- 为什么有圣诞老人的传说(为什么现在的圣诞老人形象都穿着红色衣服)|今日观点
- 16.8千瓦是多少匹马力(16.2千瓦是多少马力?)_世界播资讯
- 公募上半年分红超900亿元,债基成“现金奶牛”
- 人保财险威海文登支公司组织开展反洗钱宣传工作 新资讯
- 焦点资讯:gif求出处麻豆_gif求出处
- 望变电气:公司目前订单饱和,特别是输配电及控制设备订单超出公司的产能
- 阜阳今年计划建设100个遮阳(雨)棚-世界快消息
- 微信长图片怎么分页打印(长图片怎么分页打印)
- 江西于都警方通报“一家3小孩被杀害”:犯罪嫌疑人已抓获归案|每日热门
- 涛雒镇举办“光荣在党50年”纪念章颁发暨庆“七一”文艺演出活动|视点
- 全国台联第二十届台胞青年千人夏令营江苏分营开营
- 全球即时看!终极三国2017停播原因粉丝见面会_终极三国2017停播原因
- 小学升初中成绩查询app(小学升初中成绩查询)
- pu皮的鞋子耐穿吗_pu皮鞋好不好
- 小米官网商城叫什么名字啊(小米官网商城叫什么名字) 当前报道
- 《弈仙牌》首个正式赛季“风起弈仙”现已开启! 环球看热讯
- 省卫健委防汛卫生应急工作组到湘西州指导救灾防疫工作|世界焦点
- 六盘山在哪里属于哪个省份(六盘山在哪)
- 考试后孩子说:“我只是粗心,其实我都会”,家长的回应至关重要
- “天山胜利隧道”出口端左右主洞双双突破6000米|今日热议
- 母亲说哥姐要回来过五一节,她转身订好了车票带公婆出游:赶紧逃
- lemon罗马音歌词对照_lemon罗马音歌词|独家焦点
- 世界微动态丨哈弗枭龙系列万台车辆重磅下线,凭智造实力制胜新能源未来
- 天天新动态:安全员a证和c证的难度(安全员a证b证c证区别)
- 小鹏要凭G6“绝地求生”,除了价格与配置还需要什么?_天天百事通
- 江西人喜欢吃什么? 每日速递
- 直达!沧州西至石家庄高铁开通|当前动态
- 【全球报资讯】潍柴动力:预计2023年上半年净利润约35.87亿元~40.65亿元 同比增长50%~70%
- 最新:百余新股上半年入场,15股首日涨幅翻倍,这些板块“肉签”频出
- 郑州市总工会明日开启职工普惠服务“三重礼”_快播报
- 热点聚焦:为什么很多好吃的东西都容易让人发胖?
- 今日关注:深夜突发!蔡某某,被点名!
- 【环球热闻】小米触控笔总是断连
- 150是移动还是联通?_150是啥移动还是联通|全球视讯
- 观热点:首都机场复航北京至慕尼黑航线
- 《权游》「龙妈」出演的漫威新剧被骂惨了,罪魁祸首是 AI ?_视讯
- 每日资讯:投行"中考"放榜!冠军换人,马太效应更明显,IPO增量不增规模,单家募资下滑
- 创业板互联金融概念股有哪几家?_世界热讯