从字节码看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 的隐式传参的更多相关文章

  1. 从字节码看java类型转换【 深入理解 (T[]) new Object[size] 】

    我们都知道,java中对类型的检查是很严格的,所以我们平操作时,也往往很小心. 如题: (T[]) new Object[size],这种写法是一般我们是不会干的!但是有点经验的同学,还是会遇到这样写 ...

  2. 通过字节码分析java中的switch语句

    在一次做题中遇到了switch的问题,由于对switch执行顺序的不了解,在这里简单的通过字节码的方式理解一下switch执行顺序(题目如下): public class Ag{ static pub ...

  3. 从源码看java中Integer的缓存问题

    在开始详细的说明问题之前,我们先看一段代码 public static void compare1(){ Integer i1 = 127, i2 = 127, i3 = 128, i4 = 128; ...

  4. java中调用三方接口post传参时map和jsonobject的区别转换

    post方法名及参数为:(具体方法可参考https://www.cnblogs.com/mufengforward/p/10510337.html) public static String doPo ...

  5. java中类型的隐式转换

    byte+byte=int,低级向高级是隐式类型转换,高级向低级必须强制类型转换,byte<char<short<int<long<float<double

  6. 从源码浅析Java中的Lock和AbstractQueuedSynchronizer

    在之前的文章中我也曾经介绍过Lock,像ReentrantLock(可重入锁)和ReentrantReadWriteLock(可重入读写锁),这些所我们在说的时候并没有详细的说明它们的原理,仅仅说明了 ...

  7. F#中的自定义隐式转换

    我们知道隐式变换在可控情况下会使代码变得简洁.熟悉C#的都知道C#中可以自定义隐式变换,例如 public class A { private int data; public static impl ...

  8. SQL Server中提前找到隐式转换提升性能的办法

        http://www.cnblogs.com/shanksgao/p/4254942.html 高兄这篇文章很好的谈论了由于数据隐式转换造成执行计划不准确,从而造成了死锁.那如果在事情出现之前 ...

  9. vue-cli项目中使用全局过滤器及传参(日期格式化)

    // 过滤日期格式,传入时间戳,根据参数返回不同格式 const formatTimer = function(val, hours) { if (val) { ); var y = dateTime ...

随机推荐

  1. 【aardio】如何对listview中某一列,某一行的特定值进行修改?

    用表格创建数组来实现. import win.ui; /*DSG{{*/ var winform = ..win.form( bottom=399;parent=...;right=599;text= ...

  2. LR 11录制IE起不来

    注:LR 11一般使用的是IE8或IE9 1.在录制脚本时Start Recoding中,默认如下,这样有可能IE打不开,需要更改路径,到对应的IE路径再尝试. 2.降低IE版本到IE8或者9 3.I ...

  3. npm-package.json

    Specifics of npm's package.json handling DESCRIPTION§ This document is all you need to know about wh ...

  4. NOVO SOP (SOP简介及历史)

    SOP(Standard Operation Procedure),标准作业程序. 一.什么是SOP(标准作业程序) 所谓SOP,是 Standard Operation Procedure三个单词中 ...

  5. python 练习4

    题目为信用卡消费管理系统: 主程序:main.py #!usr/bin/env python # encoding: utf-8 import conf,sys,time,re,os import j ...

  6. EmWin 文本显示函数

    函数模型----------------------------------- 1:void GUI_DispChar(U16 c):  在当前窗口的当前文本位置处,使用当前字体显示单个字符.  c ...

  7. 【NIFI】 Apache NiFI 授权配置

    当NIFI未配置需要单向SSL(例如LDAP,OpenId Connect等)的替代认证机制时,NiFi的Web服务器将要求访问用户界面的用户使用基于证书的客户端身份验证.启用备用身份验证机制会将We ...

  8. Codeforces Round #539 (Div. 2) C Sasha and a Bit of Relax

    题中意思显而易见,即求满足al⊕al+1⊕…⊕amid=amid+1⊕amid+2⊕…⊕ar且l到r的区间长为偶数的这样的数对(l,r)的个数. 若al⊕al+1⊕…⊕amid=amid+1⊕amid ...

  9. #2019-2020-4 《Java 程序设计》第八周总结

    2019-2020-4 <Java 程序设计>第八周知识总结 第15章:泛型与集合框架 一.泛型 1.泛型(Generics)是可以建立具有类型安全的集合框架,如链表.散列映射等数据结构: ...

  10. 前后台分离开发时遇到循环引用问题"$ref"

    1. 遇到的问题 { "errMsg": "", "data": { "baseinfo": { "freeT ...