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

2025-05-29 0 37

前言

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

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

概述

  • this关键字,是一个隐式参数,另外一个隐式参数是super。
  • this用于方法里面,用于方法外面无意义。
  • this关键字一般用于set方法和构造方法中。

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

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

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19
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);

}

}

反汇编命令:

?

1
javap -verbose hello.class

反汇编结果:

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

154

155

156

157

158
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

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."<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

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."<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

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, 然后再做相关操作!

总结:

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

原文链接:http://www.cnblogs.com/yougewe/p/9929249.html

收藏 (0) 打赏

感谢您的支持,我会继续努力的!

打开微信/支付宝扫一扫,即可进行扫码打赏哦,分享从这里开始,精彩与您同在
点赞 (0)

声明:本站所有文章,如无特殊说明或标注,均为本站原创发布。任何个人或组织,在未征得本站同意时,禁止复制、盗用、采集、发布本站内容到任何网站、书籍等各类媒体平台。如若本站内容侵犯了原著者的合法权益,可联系我们进行处理。

快网idc优惠网 建站教程 通过字节码看java中this的隐式传参详解 https://www.kuaiidc.com/110700.html

相关文章

发表评论
暂无评论