Java字节码揭秘——第四部分

实践中的Java字节码
对Java字节码有了一定了解之后,我们可以来看看一些常用的和熟悉的Java语言的内容是如何与字节码映射的,也可以获得一些Java实现的细节内容。
 
Java 5:自动封装(autoboxing)
Java 5版本的一个新特性是自动封装(autoboxing),基础数据类型因语义环境的需要能转换成为对象类型,例如:
 
public class Autoboxing{        public static void main(String[] args)        {               int x = 5;               java.util.ArrayList al = new java.util.ArrayList();               al.add(x);        }}
在Java 5之前,这样的写法是错误的,因为x并不是对象。在Java 5下,编译后的字节码如下:
 
0: iconst_51: istore_12: new #2; //class java/util/ArrayList5: dup6: invokespecial #3; //Method java/util/ArrayList."<init>":()V9: astore_210: aload_211: iload_112: invokestatic #4; //Method java/lang/Integer.valueOf:(I)Ljava/lang/Integer;15: invokevirtual #5; //Method java/util/ArrayList.add:(Ljava/lang/Object;)Z18: pop19: return
编号为0的行将整数常量5推送至堆栈,编号为1的行将堆栈顶端的5存储至第一个本地分片中。接下来,有四个操作符指令,new/dup/invokespecial/astore,是通常用来新创建对象并存储在本地变量中的做法。接下来,在编号为10的行,将ArrayList的引用推送至队战,然后再将x本地的值推送至堆栈。编号为12的行我们看到Java调用了静态的Integer.valueOf方法,它需要一个单独的堆栈分片,并消费整数值5,然后将包含着5的Integer对象推送到位。然后,这个对象就成为了add方法的参数,调用add方法就消费了Integer和ArrayList的引用,并将add方法的返回值推送回堆栈。
 
内部类(Inner Class)
在JDK 1.1发布时,Sun引入了内部类,支持创建与外部类有着特殊的私有可见关系的嵌套类。JVM并未引入像C++那样的friend功能,这就有点让Java使用者有个疑惑:在JVM本身强迫私有访问性时,而且把内部类看作跟其他类一样,Java如何对类的访问进行授权?
 
在下面这个例子中,内部类显然可以访问外部类的data私有属性:
 
class Outer{        private int data = 12;        public Inner getInner()        {               return new Inner();        }        public class Inner        {               public int getData()               {                       return data;               }        }} public class NestedFun{        public static void main(String[] args)        {               Outer o = new Outer();               Outer.Inner i = o.getInner();               System.out.println(i.getData());               // prints 12; how?        }}
对于这段代码,编译器如何进行工作呢?我们从NestedFun.main(String[])开始看字节码:
 
public static void main(java.lang.String[]);        Code:               Stack=2, Locals=3, Args_size=1               0: new #2; //class Outer               3: dup               4: invokespecial #3; //Method Outer."<init>":()V               7: astore_1               8: aload_1               9: invokevirtual #4; //Method Outer.getInner:()LOuter$Inner;               12: astore_2               13: getstatic #5; //Field java/lang/System.out:Ljava/io/PrintStream;               16: aload_2               17: invokevirtual #6; //Method Outer$Inner.getData:()I               20: invokevirtual #7; //Method java/io/PrintStream.println:(I)V               23: return
这段字节码还是比较直接的:Java使用了常用的new/dup/invokespecial/astore组合来创建Outer的实例,对Outer.getInner()和getData()的调用,其中对getData()调用的返回值直接传入了println()方法(注意,编译器选择先获取System.out,然后再是getData(),所以才能保证执行堆栈的位置顺序正确)。这一段基本没啥,我们再来看Outer.Inner.getDate()方法:
 
public class Outer$Inner extends java.lang.Object        SourceFile: "NestedFun.java"        InnerClass:               public #21= #4 of #18; //Inner=class Outer$Inner of class Outer        minor version: 0        major version: 50        Constant pool: (snipped) {final Outer this$0; public Outer$Inner(Outer);        Code:               Stack=2, Locals=2, Args_size=2               0: aload_0               1: aload_1               2: putfield #1; //Field this$0:LOuter;               5: aload_0               6: invokespecial #2; //Method java/lang/Object."<init>":()V               9: return public int getData();        Code:               Stack=1, Locals=1, Args_size=1               0: aload_0               1: getfield #1; //Field this$0:LOuter;               4: invokestatic #3; //Method Outer.access$000:(LOuter;)I               7: ireturn}
这是去掉了一些输出后的结果,以便阅读。首先,我们看到了在Java规范中的“outer this”引用被显式加入内部类中作为一个属性,名为“this$0”,并标记为final。其次,编译器也生成了内部类的构造函数,用一个外部类的引用为“outer this”赋值,所以我们可以假定在外部类的getInner()方法中的new Inner()会用到本构造函数。第三,在内部类的getData()方法上,访问了一个外部类的静态方法叫“access$000”,来获取数据。
 
紧接着,我们可以看看外部类。
 
class Outer extends java.lang.Object{private int data; Outer();        Code:               0: aload_0               1: invokespecial #2; //Method java/lang/Object."<init>":()V               4: aload_0               5: bipush 12                7: putfield #1; //Field data:I               10: return public Outer$Inner getInner();        Code:               0: new #3; //class Outer$Inner               3: dup               4: aload_0               5: invokespecial #4; //Method Outer$Inner."<init>":(LOuter;)V               8: areturn static int access$000(Outer);        Code:               0: aload_0               1: getfield #1; //Field data:I               4: ireturn}
我们可以看见编译器生成了一个静态方法专为访问data开了个口子,不过“access$000”是包内私有的,也就是说在同包内的类才能访问该方法。
 
Java字节码工具
Java字节码功能工具很多,包括:
Javassist
Jasmin
……
 
也许,最重要的拆解字节码的工具还是javap。


本文来自优快云博客,转载请标明出处:http://blog.youkuaiyun.com/BU_BetterYou/archive/2008/06/19/2564105.aspx

【异常】API 速率限制报错问题全流程排查与解决指南 API rate limit reached. Please try again later. 摘要: 本文针对大模型API开发中常见的速率限制报错("API rate limit reached")提供全流程解决方案。首先解析该报错的本质是服务端对高频调用的保护机制,通过三步排查法确认根因:客户端请求频率超出账户阈值。提出三级解决方案:1)临时等待限流周期重置;2)升级付费账户提高调用配额;3)构建多模型容灾架构实现自动切换。建议生产环境优先采用容灾方案,通过备用API节点保障业务连续性,同时平衡不同模型服务的成本与性能。 阅读详情

相关推荐

在Ubuntu上通过Wine完美运行企业微信的详细指南

本文提供了在Ubuntu系统上通过Wine兼容层安装和运行企业微信的详细教程。针对官方未提供Linux版本的痛点,指南推荐使用Ubuntu Kylin团队优化打包的Wine环境,通过简单的命令行步骤即可完成部署,并涵盖启动、中文输入法配置、文件管理等常见问题的解决方案,帮助用户实现高效、稳定的办公沟通。

weixin_29306317的博客 231

javap—跟在new指令屁股后面的dup指令

每当我查看反编译结果时,经常会看到 dup 字节码指令跟在 new 字节码指令之后,又不知道它是干嘛的,很影响阅读,所以就有了这篇博客~ JVM 中的字节码指令操作是基于操作数栈的,栈操作一个数据只能通过先出栈计算,再将结果压栈的方式。操作数栈主要用于保存执行过程的中间结果:配合局部变量表,将中间结果保存在变量槽中;需要使用局部变量时,读取局部变量表对应变量槽中的元素压入栈顶再出栈。 以下代码创建了 CreateObjectTest 对象,并使用局部变量 createObjectTest 保存实例的引用。

qq_44707077的博客 729

发那科机器人Modbus通讯配置全攻略:从IP设置到信号调试

本文详细介绍了发那科机器人Modbus通讯的配置方法,从基础认知到IP设置、端口配置、信号调试及故障排查。重点讲解了UOP和DI/DO信号的配置技巧,帮助工程师快速实现机器人与PLC的稳定通讯,提升自动化系统效率。

weixin_27872611的博客 621

Java字节码,字节码指令

各种字节码指令的相关介绍,方法重载和重写在字节码层面的实现原理和机制,字节码的查看和分析方法简单介绍

m0_66668867的博客 1748

Unity中URP下的菲涅尔效果实现(个性化修改)

在上篇文章中,我们实现了 URP 下的菲涅尔基础效果,我们在这篇文章中,对其进行自定义化修改。

楠溪泽岸的博客 2063

【ENVI初学】查看影像空间分辨率及重采样

例如,如果线段长度为900米,对应的像素数量为30个,那么影像的空间分辨率为30米。通过计算长度与像素数量的比值,即可得到影像的空间分辨率。,在弹出的对话框中,输入重采样后输出文件的xy分辨率大小。在测量结果窗口中,可以看到该线段的长度以及角度。在影像上点击并拖动鼠标,绘制一条直线段。工具,选择要重采样的影像后点击ok。,避免了插值过程中光谱信息的改变。:最近邻插值法通过选择原始影像中。在ENVI中打开影像后右键选择。指示了每个像素的地理跨度(聚合为一个新像素,通常通过。方法一:查看影像的元数据。

weixin_41619112的博客 5571

反编译出现access$分析

1)static Type access$iii(Outer); 是JAVA编译器自动生成的十分重要的方法(该方法的个数由你的内部类要访问的外部类的变量个数相关),目的是:用于内部类访问外部类的数据成员时使用. 2)因此:JAVA编译器在生成内部类的访问外部类的数据成员时,会自动生成代码来调用这个方法. 以你的代码为例:内部类Inner中的方法 public int getDate() 

andylao62的专栏 1万+

TriCore架构-基于TC397的启动流程

TC397芯片的启动流程分为三个关键阶段:固件启动(BootFirmware)、Bootloader引导和应用程序启动。BootFirmware作为硬件信任根,包含SSW基础初始化、CHSW自检和BSL应急刷写通道。Bootloader承担安全验证和程序引导功能,支持双分区(AB-SWAP)和双引导方案(PBL/SBL)。安全启动通过校验机制确保软件完整性,提供三种可选技术方案。应用程序启动阶段实现软件双分区管理,支持SOTA更新。整个流程体现了汽车电子系统的安全设计理念,通过硬件级保护与软件验证相结合确保

xiandang8023的博客 987

Java JVM 字节码-为什么 new 指令后执行 dup 指令?

专栏原创出处:github-源笔记文件 ,github-源码 ,欢迎 Star,转载请附上原文出处链接和本声明。 Java JVM-虚拟机专栏系列笔记,系统性学习可访问个人复盘笔记-技术博客 Java JVM-虚拟机 为什么 new 指令后执行 dup 指令? 关于字节码相关问题,可参考本专栏相关文章。在此不做介绍,直接进行分析。 在做字节码分析时,发现每次 new 指令后跟随着 dup ...

2.wa 4960

Electron - Electron failed to install correctly, please delete node_modules/electron and try install

Electron安装失败:Electron failed to install correctly, please delete node_modules/electron and try installing again,electron安装报错:Electron failed to install correctly...解决方案,Electron 未能正确安装,请删除 node_modules/electron,然后再次尝试安装,如何解决这个问题,手把手教你解决,在yarn dev时报错,electr

🏆 前端领域优质创作者 4367

使用 Simulink 进行电力电子系统的小信号模型仿真

电力电子系统(Power Electronics System)包括各种功率转换器(如 DC-DC 转换器、逆变器等)。这些设备中的关键组件(如 MOSFET、IGBT、电容器、电感器等)不仅影响系统的性能,还直接关系到系统的稳定性、效率和可靠性。因此,在设计阶段进行详细的建模和仿真至关重要。小信号模型仿真的目的是通过线性化非线性系统来评估其动态特性,包括增益、相位裕度、带宽等指标。通过本教程,我们介绍了如何使用 Simulink 进行电力电子系统的小信号模型仿真。背景介绍。

xiaoheshang_123的博客 480

Java字节码new之后为什么会有dup

在看《深入理解Java虚拟机:JVM高级特性与最佳实践(第二版)》这本书时,有几处的字节码在new之后会紧接着出现dup指令,我么以书中253页的字节码为例,说明dup指令的作用。 其中Java代码为: public class DynamicDispatch { static abstract class Human { protected abstract void sayHello(...

dabusiGin的博客 1300

全国(山东、安徽)职业技能大赛--信息安全管理与评估大赛题目+答案讲解——windows应急响应篇

保护数据,捍卫安全,展现技能,赢得荣耀!全国职业技能大赛-信息安全与评估大赛,挑战你的技术,揭示黑客的秘密!加入我们,成为信息安全的守护者!

人若无名,便可专心练剑 907

Java字节码

Java最黑科技的玩法就是字节码编程,也就是动态修改或是动态生成 Java 字节码。使用字节码可以玩出很多高级的玩法,最高级的还是在 Java 程序运行时进行字节码修改和代码注入。听起来是不是一些很黑客,也很黑科技的事?是的,这个方式使用 Java 这门静态语言在运行时可以进行各种动态的代码修改,而且可以进行无侵入的编程。 比如,我们不需要在代码中埋点做统计或监控,可以使用这种技术把我们的监控代码...

螃蟹士兵 1万+

SAP B1中文培訓教材_SDK

公司内部培训资料,对开发工具 ,DIAPI, UIAPI,Add-ON有详细解说

Camera2Demo

在Camera2 的基础上进行封装,使得Camera2一堆初始化逻辑与Activity分离,降低耦合度,完成预览拍照并保存的操作

JAVA字节码分析

以下是Java字节码(.classJava字节码是基于的二进制流,按顺序紧凑排列,无分隔符。

Android资深专家,chromium 内核开发者 1242

efm32 入门.pdf

本PDF共计22页,介绍的是操作驱动API,下载与否自己斟酌。

java字节码

Java之所以可以“一次编译,到处运行”,一是因为JVM针对各种操作系统、平台都进行了定制,二是因为无论在什么平台,都可以编译生成固定格式的字节码(.class文件)供JVM使用。因此,也可以看出字节码对于Java生态的重要性。之所以被称之为字节码,是因为字节码文件由十六进制值组成,而JVM以两个十六进制值为一组,即以字节为单位进行读取。

zhangjunli的博客 2555

蓝牙模块HM-10手册

蓝牙模块HM-10手册,该手册对蓝牙模块HM-10进行了详细的介绍和使用方法以及一些AT指令。

详解JAVA字节码

一文详解JAVA字节码

BugMan的博客 3380

揭秘 Java 字节码理解 JVM 的工作原理

下面这篇文章面向有 Java 基础但对 JVM 内部、字节码(bytecode)与运行机制不够熟悉的读者。文章分层次讲解核心概念,并通过代码实战展示怎么生成、查看与逐步理解字节码,帮助你把抽象概念变成可操作的技能。

一键难忘的博客 1370

Java字节码揭秘——第一部分

 写在前面这一两年,在JVM上使用其他替代语言越来越热门了。现在至少有三门语言有幸在Java Community Process中得到了官方认可:JRuby、Groovy和Bean-Shell。另外,代号为野马(Mustang)的Java 6发布了包含了一个专为封装不同脚本引擎的API层,就像JDBC访问数据库的模式一样。再加上Java版本5也在语言本身上做了很大的调整。总之,就像我之前翻

BU_BetterYou的专栏 1万+

Java字节码揭秘——第二部分

 Java字节码分类JVM字节码集合基本上是分为几个不同的大类的。我们不会逐一介绍字节码的操作符,我们讨论类别,然后着重拿出一些常用的操作符,其余的均可通过JVM规范来获取详情。 堆栈操作。 pop、pop2:将堆栈的值弹出。pop2用来弹出64位的值,pop用来弹出32位的。 dup、dup2:复制堆栈顶端的值。用来形成高效的pop/push/push组

BU_BetterYou的专栏 3914

读懂Java字节码

目录 一、简单demo分析 字节码文件信息 常量池 方法表集合 二、分析try-catch-finally的demo 计算机只认识0和1。这意味着任何语言编写的程序最终都需要经过编译器编译成机器码才能被计算机执行。所以,我们所编写的程序在不同的平台上运行前都要经过重新编译才能被执行。 而Java刚诞生的时候曾经提过一个非常著名的宣传口号: "一次编写,到处运行"。为了实现该目的,Sun...

l1394049664的博客 6848

《字节码运行机制揭秘:反射、代理、Javassist 原理与实战》

本文深入解析Java字节码运行机制及其关键技术应用。文章首先介绍了JVM执行引擎工作流和字节码结构,通过.class文件格式和反编译示例展示字节码指令执行过程。重点剖析了反射机制的核心流程和性能优化方法,对比了不同调用方式的性能损耗。在动态代理方面,详细讲解了JDK动态代理实现原理,并与CGLIB进行特性对比。最后通过Javassist和ASM的实战示例,演示了运行时字节码修改技术,包括动态创建类和方法增强等高级应用场景。全文构建了从原理到实践的完整知识体系,为理解Java动态能力提供了技术支撑。

qq_43414012的博客 1113

【潜意识Java】深度探索Java字节码

家人们,今天来深挖 Java 中极为底层却又无比关键的部分 —— 字节码。平常我们编写 Java 代码,可能很少直接接触字节码,但它却是 Java 程序运行的基石。理解字节码,能让你透彻明白 Java 程序是如何在虚拟机里运行的,无论是排查问题,还是优化代码,都离不开它。我也是在不断钻研中才把它摸透,现在就把这些宝贵经验分享给大伙。

潜意识Java的博客 853

JVM-Java字节码的组成部分

字节码文件的结构和内容是由Java编译器生成的,而JVM负责解释和执行这些字节码指令。常量池是Java字节码文件的一个重要部分,它包含了各种常量,如字符串、类和字段引用、方法描述符等。常量池是一个表格结构,每个常量都有一个索引,通过这个索引可以在常量池中查找具体的常量。Java字节码文件是一种由Java编译器生成的二进制文件,用于在Java虚拟机(JVM)上执行Java程序。方法定义包括方法的访问修饰符、名称、方法描述符(参数类型和返回类型的描述)、方法的字节码指令序列以及异常表。

m0_51663233的博客 674

什么是Java字节码?

什么是字节码? Java之所以可以“一次编译,到处运行”,一是因为JVM针对各种操作系统、平台都进行了定制,二 是因为无论在什么平台,都可以编译生成固定格式的字节码(.class文件)供JVM使用。因此,也可以看 出字节码对于Java生态的重要性。之所以被称之为字节码,是因为字节码文件由十六进制值组成,而 JVM以两个十六进制值为一组,即以字节为单位进行读取。在Java中一般是用javac命令编译源代码为字 节码文件。 对于开发人员,了解字节码可以更准确、直观地理解Java语言中更深层次的东西,比如通过

wangkexiang21的博客 3599
上一篇: Java字节码揭秘——第三部分
下一篇: Java EE应用中的性能问题解决方案 — 第一部分 内存溢出和JVM内幕(A)
topinking
博客等级 码龄20年 15粉丝 242原创
评论
成就一亿技术人!
拼手气红包6.0元
还能输入1000个字符
 
 条评论被折叠 查看
添加红包

请填写红包祝福语或标题

个

红包个数最小为10个

元

红包金额最低5元

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

抵扣说明:

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

余额充值