前言
從字節(jié)碼看java中 this 隱式傳參具體體現(xiàn)(和python中的self如出一轍,但是比python中藏得更深),也發(fā)現(xiàn)了 static 與 非 static 方法的區(qū)別所在!
static與非static方法都是存儲java的方法區(qū)。在static 方法中,沒有this引用,因此無法使用當前類中所定義的變量,而非static方法則會默認傳入this。
概述
- this關(guān)鍵字,是一個隱式參數(shù),另外一個隱式參數(shù)是super。
- this用于方法里面,用于方法外面無意義。
- this關(guān)鍵字一般用于set方法和構(gòu)造方法中。
我們今天就從另一個角度來真實看一下這個答案吧!
來個例子,并將其反編譯為可視代碼:
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 |
反匯編結(jié)果:
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" |
我們從字節(jié)碼文件中可以看出來:
sayhello(string word) 和 sayhellostatic(string word) 都只有一個參數(shù),但是在字節(jié)碼中:
sayhello(string word) 中引用 word 時使用了 15: aload_1, 可以看出其加載的變量是在 slot1中,而 slot0中即保存了 this 。
sayhellostatic(string word) 中引用 word 時使用了 15: aload_0, 可以看出靜態(tài)方法中,直接將變量存在了 slot0中,因此無法使用 this 中的變量了。
當要操作當前類的變量或方法時,需要先 aload_0, 然后再做相關(guān)操作!
總結(jié):
以上就是這篇文章的全部內(nèi)容了,希望本文的內(nèi)容對大家的學習或者工作具有一定的參考學習價值,如果有疑問大家可以留言交流,謝謝大家對服務器之家的支持。
原文鏈接:http://www.cnblogs.com/yougewe/p/9929249.html