从字节码看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.class
Last modified 2018-11-8; size 1069 bytes
MD5 checksum 9d39cd9d4e95588a73c059a4e69f01e8
Compiled from "Hello.java"
public class com.xx.api.Hello
minor version: 0
major version: 52
flags: 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)V
flags: ACC_PUBLIC
Code:
stack=2, locals=2, args_size=2
0: aload_0
1: invokespecial #1 // Method java/lang/Object."<init>":()V
4: aload_0
5: iload_1
6: putfield #2 // Field ii:I
9: return
LineNumberTable:
line 14: 0
line 15: 4
line 16: 9
LocalVariableTable:
Start Length Slot Name Signature
0 10 0 this Lcom/xx/api/Hello;
0 10 1 a I public static void main(java.lang.String[]) throws java.lang.Exception;
descriptor: ([Ljava/lang/String;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=1, locals=1, args_size=1
0: ldc #3 // String ok
2: invokestatic #4 // Method sayHelloStatic:(Ljava/lang/String;)V
5: return
LineNumberTable:
line 42: 0
line 45: 5
LocalVariableTable:
Start Length Slot Name Signature
0 6 0 args [Ljava/lang/String;
Exceptions:
throws java.lang.Exception public void sayHello(java.lang.String);
descriptor: (Ljava/lang/String;)V
flags: ACC_PUBLIC
Code:
stack=3, locals=2, args_size=2
0: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #6 // class java/lang/StringBuilder
6: dup
7: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V
10: ldc #8 // String hello,
12: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: aload_1
16: 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;)V
25: return
LineNumberTable:
line 48: 0
line 49: 25
LocalVariableTable:
Start Length Slot Name Signature
0 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;)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=1, args_size=1
0: getstatic #5 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #6 // class java/lang/StringBuilder
6: dup
7: invokespecial #7 // Method java/lang/StringBuilder."<init>":()V
10: ldc #12 // String static hello,
12: invokevirtual #9 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: aload_0
16: 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;)V
25: return
LineNumberTable:
line 51: 0
line 52: 25
LocalVariableTable:
Start Length Slot Name Signature
0 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 的隐式传参的更多相关文章
- 从字节码看java类型转换【 深入理解 (T[]) new Object[size] 】
我们都知道,java中对类型的检查是很严格的,所以我们平操作时,也往往很小心. 如题: (T[]) new Object[size],这种写法是一般我们是不会干的!但是有点经验的同学,还是会遇到这样写 ...
- 通过字节码分析java中的switch语句
在一次做题中遇到了switch的问题,由于对switch执行顺序的不了解,在这里简单的通过字节码的方式理解一下switch执行顺序(题目如下): public class Ag{ static pub ...
- 从源码看java中Integer的缓存问题
在开始详细的说明问题之前,我们先看一段代码 public static void compare1(){ Integer i1 = 127, i2 = 127, i3 = 128, i4 = 128; ...
- java中调用三方接口post传参时map和jsonobject的区别转换
post方法名及参数为:(具体方法可参考https://www.cnblogs.com/mufengforward/p/10510337.html) public static String doPo ...
- java中类型的隐式转换
byte+byte=int,低级向高级是隐式类型转换,高级向低级必须强制类型转换,byte<char<short<int<long<float<double
- 从源码浅析Java中的Lock和AbstractQueuedSynchronizer
在之前的文章中我也曾经介绍过Lock,像ReentrantLock(可重入锁)和ReentrantReadWriteLock(可重入读写锁),这些所我们在说的时候并没有详细的说明它们的原理,仅仅说明了 ...
- F#中的自定义隐式转换
我们知道隐式变换在可控情况下会使代码变得简洁.熟悉C#的都知道C#中可以自定义隐式变换,例如 public class A { private int data; public static impl ...
- SQL Server中提前找到隐式转换提升性能的办法
http://www.cnblogs.com/shanksgao/p/4254942.html 高兄这篇文章很好的谈论了由于数据隐式转换造成执行计划不准确,从而造成了死锁.那如果在事情出现之前 ...
- vue-cli项目中使用全局过滤器及传参(日期格式化)
// 过滤日期格式,传入时间戳,根据参数返回不同格式 const formatTimer = function(val, hours) { if (val) { ); var y = dateTime ...
随机推荐
- VUEX报 “was assigned to but it has no setter”
如果有当前的变量(VUEX声名的)会发生改变的(change),刚绑定的值需要在data () 内进行声明 一个新的变量进行处理.
- bootstrap treeview 树形数据生成
这个问题还是挺经典的,后台只是负责查出所有的数据,前台js来处理数据展示给treeview;show you the code below:<script> $(function () { ...
- 云计算底层技术-虚拟网络设备(Bridge,VLAN)( 转发)
云计算底层技术-虚拟网络设备(Bridge,VLAN) Posted on September 24, 2017 by opengers in openstack openstack底层技术-各种虚拟 ...
- 进程&线程(转)
(摘自:http://www.cnblogs.com/CareySon/archive/2012/05/04/ProcessAndThread.html) 在传统的操作系统中,进程拥有独立的内存地址空 ...
- 腾讯开源的Paxos库PhxPaxos代码解读---Prepare阶段(一)
简单的画了一下PhxPaxos在Prepare阶段的逻辑,主要是正常的逻辑,异常逻辑和超时后面再写了; 熟悉PhxPaxos代码最好的方法是编译运行sample目录下的三个例子,编译方法在另一篇博客已 ...
- 图解Go select语句原理
Go 的select语句是一种仅能用于channl发送和接收消息的专用语句,此语句运行期间是阻塞的:当select中没有case语句的时候,会阻塞当前的groutine.所以,有人也会说select是 ...
- 启动tomcat报错com.sun.faces.config.ConfigureListener
小白一个,最近想着上网看看自己搭建个用maven+spring+springmvc+mybaties的框架 然后......就出来这个么东东 java.lang.ClassNotFoundExcept ...
- HTML标签有序标签和无序标签
1.<ul>标签定义无序列表,所谓无序,是指以●.○.▽.▲等开头的,没有顺序的列表项目 1.1 设置无序列表的类型—type 无序列表的默认符号是圆点(● ). ...
- Codeforces 837 简要题解
文章目录 A题 B题 C题 D题 E题 F题 G题 传送门 并没有找到难度评级但感觉是div3div3div3场. A题 题意:一个单词的价值是里面大写字母的个数,一篇文章的价值是里面所有单词的价值的 ...
- mybatis-plus 3.X 配置
官网配置参数说明地址:https://mp.baomidou.com/config/#logicdeletevalue 本地配置:yml mybatis-plus: mapper-locations: ...