java this 参数传入_通过字节码看java中this的隐式传参详解

前言

从字节码看java中 this 隐式传参具体体现(和python中的self如出一辙,但是比python中藏得更深),也发现了 static 与 非 static 方法的区别所在!

static与非static方法都是存储java的方法区。在static 方法中,没有this引用,因此无法使用当前类中所定义的变量,而非static方法则会默认传入this。

概述

this关键字,是一个隐式参数,另外一个隐式参数是super。

this用于方法里面,用于方法外面无意义。

this关键字一般用于set方法和构造方法中。

我们今天就从另一个角度来真实看一下这个答案吧!

来个例子,并将其反编译为可视代码:

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."":()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."":()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

#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 // "":()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."":()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

10 0 this Lcom/xx/api/Hello;

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

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."":()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

26 0 this Lcom/xx/api/Hello;

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."":()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

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 中的变量了。

当要操作当前类的变量或方法时,需要先 aload_0, 然后再做相关操作!

总结:

以上就是这篇文章的全部内容了,希望本文的内容对大家的学习或者工作具有一定的参考学习价值,如果有疑问大家可以留言交流,谢谢大家对脚本之家的支持。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值