从字节码看java中 this 的隐式传参
从字节码看java中 this 隐式传参具体体现(和python中的self如出一辙,但是比python中藏得更深),也发现了 static 与 非 static 方法的区别所在!
static与非static方法都是存储java的方法区。在static 方法中,没有this引用,因此无法使用当前类中所定义的变量,而非static方法则会默认传入this。我们今天就从另一个角度来真实看一下这个答案吧!
来个例子,并将其反编译为可视代码:
public class Hello {private final int ii;public Hello(int a) {ii = a;}public static void main(String[] args) throws Exception {sayHelloStatic("ok");}public void sayHello(String word) {System.out.println("hello, " + word);}public static void sayHelloStatic(String word) {System.out.println("static hello, " + word);} }
反汇编命令:
javap -verbose Hello.class
反汇编结果:
Classfile /D:/xx/target/classes/com/xx/api/Hello.classLast modified 2018-11-8; size 1069 bytesMD5 checksum 9d39cd9d4e95588a73c059a4e69f01e8Compiled from "Hello.java" public class com.xx.api.Hellominor version: 0major version: 52flags: ACC_PUBLIC, ACC_SUPER Constant pool:#1 = Methodref #14.#38 // java/lang/Object."<init>":()V#2 = Fieldref #13.#39 // com/xx/api/Hello.ii:I#3 = String #40 // ok#4 = Methodref #13.#41 // com/xx/api/Hello.sayHelloStatic:(Ljava/lang/String;)V#5 = Fieldref #42.#43 // java/lang/System.out:Ljava/io/PrintStream;#6 = Class #44 // java/lang/StringBuilder#7 = Methodref #6.#38 // java/lang/StringBuilder."<init>":()V#8 = String #45 // hello,#9 = Methodref #6.#46 // java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;#10 = Methodref #6.#47 // java/lang/StringBuilder.toString:()Ljava/lang/String;#11 = Methodref #48.#49 // java/io/PrintStream.println:(Ljava/lang/String;)V#12 = String #50 // static hello,#13 = Class #51 // com/xx/api/Hello#14 = Class #52 // java/lang/Object#15 = Utf8 ii#16 = Utf8 I#17 = Utf8 <init>#18 = Utf8 (I)V#19 = Utf8 Code#20 = Utf8 LineNumberTable#21 = Utf8 LocalVariableTable#22 = Utf8 this#23 = Utf8 Lcom/xx/api/Hello;#24 = Utf8 a#25 = Utf8 main#26 = Utf8 ([Ljava/lang/String;)V#27 = Utf8 args#28 = Utf8 [Ljava/lang/String;#29 = Utf8 Exceptions#30 = Class #53 // java/lang/Exception#31 = Utf8 sayHello#32 = Utf8 (Ljava/lang/String;)V#33 = Utf8 word#34 = Utf8 Ljava/lang/String;#35 = Utf8 sayHelloStatic#36 = Utf8 SourceFile#37 = Utf8 Hello.java#38 = NameAndType #17:#54 // "<init>":()V#39 = NameAndType #15:#16 // ii:I#40 = Utf8 ok#41 = NameAndType #35:#32 // sayHelloStatic:(Ljava/lang/String;)V#42 = Class #55 // java/lang/System#43 = NameAndType #56:#57 // out:Ljava/io/PrintStream;#44 = Utf8 java/lang/StringBuilder#45 = Utf8 hello,#46 = NameAndType #58:#59 // append:(Ljava/lang/String;)Ljava/lang/StringBuilder;#47 = NameAndType #60:#61 // toString:()Ljava/lang/String;#48 = Class #62 // java/io/PrintStream#49 = NameAndType #63:#32 // println:(Ljava/lang/String;)V#50 = Utf8 static hello,#51 = Utf8 com/xx/api/Hello#52 = Utf8 java/lang/Object#53 = Utf8 java/lang/Exception#54 = Utf8 ()V#55 = Utf8 java/lang/System#56 = Utf8 out#57 = Utf8 Ljava/io/PrintStream;#58 = Utf8 append#59 = Utf8 (Ljava/lang/String;)Ljava/lang/StringBuilder;#60 = Utf8 toString#61 = Utf8 ()Ljava/lang/String;#62 = Utf8 java/io/PrintStream#63 = Utf8 println {public com.xx.api.Hello(int);descriptor: (I)Vflags: ACC_PUBLICCode:stack=2, locals=2, args_size=20: aload_01: invokespecial #1 // Method java/lang/Object."<init>":()V4: aload_05: iload_16: putfield #2 // Field ii:I9: returnLineNumberTable:line 14: 0line 15: 4line 16: 9LocalVariableTable:Start Length Slot Name Signature0 10 0 this Lcom/xx/api/Hello;0 10 1 a Ipublic static void main(java.lang.String[]) throws java.lang.Exception;descriptor: ([Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=1, locals=1, args_size=10: ldc #3 // String ok2: invokestatic #4 // Method sayHelloStatic:(Ljava/lang/String;)V5: returnLineNumberTable:line 42: 0line 45: 5LocalVariableTable:Start Length Slot Name Signature0 6 0 args [Ljava/lang/String;Exceptions:throws java.lang.Exceptionpublic void sayHello(java.lang.String);descriptor: (Ljava/lang/String;)Vflags: ACC_PUBLICCode:stack=3, locals=2, args_size=20: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;3: new #6 // class java/lang/StringBuilder6: dup7: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V10: ldc #8 // String hello,12: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;15: aload_116: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;19: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;22: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V25: returnLineNumberTable:line 48: 0line 49: 25LocalVariableTable:Start Length Slot Name Signature0 26 0 this Lcom/xx/api/Hello;0 26 1 word Ljava/lang/String;public static void sayHelloStatic(java.lang.String);descriptor: (Ljava/lang/String;)Vflags: ACC_PUBLIC, ACC_STATICCode:stack=3, locals=1, args_size=10: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;3: new #6 // class java/lang/StringBuilder6: dup7: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V10: ldc #12 // String static hello,12: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;15: aload_016: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;19: invokevirtual #10 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;22: invokevirtual #11 // Method java/io/PrintStream.println:(Ljava/lang/String;)V25: returnLineNumberTable:line 51: 0line 52: 25LocalVariableTable:Start Length Slot Name Signature0 26 0 word Ljava/lang/String; } SourceFile: "Hello.java"
我们从字节码文件中可以看出来:
sayHello(String word) 和 sayHelloStatic(String word) 都只有一个参数,但是在字节码中:
sayHello(String word) 中引用 word 时使用了 15: aload_1, 可以看出其加载的变量是在 slot1中,而 slot0中即保存了 this 。
sayHelloStatic(String word) 中引用 word 时使用了 15: aload_0, 可以看出静态方法中,直接将变量存在了 slot0中,因此无法使用 this 中的变量了。
在LocalVariableTable 本地变量表中,可以清楚地看到,哪个slot存储了什么变量。
当要操作当前类的变量或方法时,需要先 aload_0, 然后再做相关操作!
从字节码看java中 this 的隐式传参相关推荐
- 7.Java中变量的隐式转换以及强类型转换
1.变量的相加,(变量的数据类型一致),直接运算即可! 结论: Java中变量的 隐式转换(数据类型的默认类型提升) byte,short,char- ...
- Java生产环境下性能监控与调优详解 第8章 JVM字节码与Java代码层调优
第8章 JVM字节码与Java代码层调优 8-1 jvm字节码指令-1 8-2 jvm字节码指令-2 8-3 i++与++i 8-4 字符串+拼接 8-5 Try-Finally字节码 8-6 Str ...
- js onclick传参对象_js中onClick([object object])的传参问题。跪求!
你的位置: 问答吧 -> JavaScript -> 问题详情 js中onClick([object object])的传参问题.跪求! 问题是这样的,看代码 for(var i=0;i ...
- sql server 中的数据类型隐式转换
数据类型转换分为隐式转换和显示转换 1)显示转换顾名思义使用函数进行数据类型转化,如cast.convert cast 和convert的区别 CAST( expression AS data_typ ...
- python调用so库输出传入指针_python中使用ctypes调用so传参设置遇到的问题及解决方法...
问题 近日在做一组声纹聚类时,使用了另一团队同学开发的声纹距离算法.该算法对外提供的是一组so包,需要使用方自己去使用.在python中调用纯so包一般使用ctypes类库,用起来看起来简单但也有不少 ...
- 怎么看java中ide_如何在eclipse IDE中查看Java的字节码?
Eclipse的默认类文件查看器显示源(参见VonC的答案),如果它已经与二进制文件相关联,否则给出类的javap样视图(具有附加源的选项).我猜这是你正在寻找的后者. 我从来没有找到一种方法来干净地 ...
- 从字节码看 finally关键字、异常表
大家好,我是烤鸭: 今天说下 finally 这个关键字. 1. 认识finally finally 总是跟 try.catch一起出现,finally是执行方法结束一定要执行的代码,比如流关闭等等 ...
- java自带的字节码技术_读懂字节码-还原JAVA源码
已知有两个类: public class Father extends GrandFather { public String name = "father"; public vo ...
- java char是几个字节_关于java中char占几个字节,汉字占几个字节
我们平常说,java中char占2个字节,可又说汉字在不通的编码格式中所占的位数是不同的,比如gbk中汉字占2个字节,utf8中多数占3个字节,少数占4个.而所有汉字在java程序中我们都可以简单的用 ...
最新文章
- 《Redis设计与实现》之第四章:字典
- 干货 | 架构师入门实战视频课程(一)
- python网络编程案例_Python 网络编程_python网络编程基础_python高级编程
- centos7防火墙firewalld配置,干货直接上手
- 【echarts】echarts开发流程详解
- 前序-中序-后序-非递归-实现
- IAAS: IT公司去IOE-Alibaba系统构架解读
- 如何在myeclipse中导入jar包?
- java8 内存设置_Java 8内存分析
- 基于深度学习的自然场景文字检测及端到端的OCR中文文字识别
- LeetCode 1004. 最大连续1的个数 III(双指针+滑动窗口)
- 显示浏览器表单输入框的缓存密码
- DBA日常管理——数据归档(Archiving-Data)
- java定义不同类型参数_java – Mockito允许使用不同的参数类型来模拟重载方法
- 对话阿里 CTO 程立:未来数字世界的根基是开源和云
- hscan扫描mysql代码_HScan 扫描器
- 代码与国家地区对照表
- 数据结构第一章概论习题及答案
- python拼图_利用python制作拼图小游戏的全过程
- 白浩然计算机学院,信息数理学院2015年上半年团员推优汇总表.doc-附件:.doc
热门文章
- ++[[]][+[]]+[+[]] == 10 //true
- windows 2012 r2 can't find kb2919355
- Linux常用到的指令汇总
- winform实现word转换为PDF(.doc)
- 今天被BSE指摘了2个问题,感觉很典型
- 删除所有的.svn 文件
- JUnit5 断言示例
- 前端快速开发插件emmet,炫技必备
- 程序的编译与链接、预处理符号、指令
- linux锁定账号 让其不能修改密码,passwd - 用于让用户可以更改自己的密码