我們一般使用的java內部類有4種形式:一般內部類、局部內部類、匿名內部類、靜態內部類。以下是我作的一個測試,以說明各種內部類的特性。
有關內部類的特性,代碼中有詳細說明,如下。
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
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
176
177
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
|
/* * java內部類測試 * * InterObj反射結果: * * private int i * private InterObj$InterA ia * public InterObj() * public static void main(java.lang.String[]) * private int getI() * public void p() * public void pi() * public void pp() * public static void ppp() * public void pppp() * 下面是編譯器自動生成用于訪問私有屬性或方法package級別的static方法 * static int access$0(InterObj) */ public class InterObj { private int i=8; private InterA ia=null; public InterObj(){ ia=new InterA(); } private int getI(){ return i; } public void p(){ pi(); pp(); ppp(); pppp(); } /* * 在一般內部類中可以訪問“外套類”中的任何級別的方法和屬性。而外套類也同樣可以 * 訪問“內部類”中的任何級別的方法和屬性。因為內部類可以持有對外套類對象的引用。 * 而“外套類”對于自己的需要被內部類訪問的私有方法和屬性,編譯器都會自動生成與 * 私有方法和屬性相對應的“package”級別的static方法,這些方法需要用外部類對象作 * 為參數,這樣就可以在“package”級別的static方法中通過訪問外套類中的私有方法和 * 屬性了。 * 而對于外套類要訪問內部類中的私有方法和屬性,也是同樣的原理,內部類在編譯時, * 會生成與需要被外套類訪問的私有方法、屬性相對應的“package”級別的static方法。 * * InterA反射結果: * private int ia * 下面是內部類持有的外套類對象引用 * final InterObj this$0 * 構造函數中用外套類對象作為參數 * InterObj$InterA(InterObj) * private void pA() * 下面是編譯器自動生成用于訪問私有屬性或方法package級別的static方法 * static void access$0(InterObj$InterA) * public void pA1() * */ class InterA{ private int ia=9; private void pA(){ System.out.println("this is InterA.pA: ia="+ia+",InterObj.i="+getI()); } public void pA1(){ System.out.println("this is InterA.pA1: ia="+ia+",InterObj.i="+getI()); } } /* * 局部內部類,只在方法內部可見,其它特性與一般內部類相同。 * 對需要訪問的局部變量,必需設置成final,因為局部內部類雖然可以持有對外套類對象的 * 引用來訪問外部類的屬性和方法,但是卻不能訪問外部類方法中局部變量,所有編譯器就 * 在局部內部類中“拷貝”了一份需要訪問的局部變量(但是對于基本類型int,float和String * 等值不發生改變的類型沒有拷貝)為了保證拷貝的變量值和外部方法中的變量的值所指向的 * 對象是同一 個對象,所以要求那些被局部類使用的局部變量應該設置成final,而不能被修 * 改,這樣來保證局部內中拷貝的變量和外部方法中的變量所指向的是同一個對象。變量設 * 置成final只是控制變量指向的對象地址不變,而不是它指向的對象的內部屬性不能改變。 * * InterB的反射結果: * * private int ib * 下面是內部類持有的外套類對象引用 * final InterObj this$0 * 下面是內部類持有的外部方法中的局部變量Test對象的引用拷貝 * private final Test val$test * 構造函數中用外套類對象和局部變量Test作為參數 * InterObj$1$InterB(InterObj,Test) * private void pB() * 下面是編譯器自動生成用于訪問私有屬性或方法package級別的static方法 * static void access$0(InterObj$1$InterB) */ public void pi(){ final int s=5; final Test test=new Test(); class InterB{ private int ib=7; private void pB(){ System.out.println("this is InterB.pB: ib="+ib+ ",(Method)pi.s="+s+",Test.t="+test.getT()); } } InterB ib=new InterB(); //此處改變了被局部內部類引用了的Test test的內部狀態。 //結果調用ib.pB()時,輸出的就是改變后的值100 test.setT(100); ib.pB(); } /* * 靜態內部類,在不需要持有對“外套類對象”的引用時使用。 * * InterC反射結果:(靜態內部類沒有對外套類對象的引用) * private int ic * InterC() * private void pC() */ static class InterC{ private int ic=6; private void pC(){ System.out.println("this is InterC.pC: ic="+ic); } } /* * 非靜態方法,可以構造靜態和非靜態的內部類。 * 可以訪問內部類中任何權限的屬性和方法 */ public void pp(){ InterA ia=new InterA(); ia.pA(); ia.pA1(); InterC ic=new InterC(); ic.pC(); //局部內部類,只在方法內部可見 //InterB ib=new InterB(); } /* * 靜態方法,只能構造靜態的內部類。 * 不能構造非靜態的內部類,因為靜態方法中沒有this來引用“外套類”的對象,來構造 * 需要引用外套類對象引用的內部類對象。 */ public static void ppp(){ //InterA ia=new InterA(); //但是可以如下構造: InterObj iobj=new InterObj(); InterA ia=iobj.new InterA(); ia.pA(); ia.pA1(); InterC ic=new InterC(); ic.pC(); //局部內部類,只在方法內部可見 //InterB ib=new InterB(); } /* * 匿名內部類測試 */ public void pppp(){ TestInterface tif=new TestInterface(){ public void pppp() { System.out.println("TestInterface.noName"); } } ; tif.pppp(); } /* * 運行結果: * this is InterB.pB: ib=7,(Method)pi.s=5,Test.t=100 * this is InterA.pA: ia=9,InterObj.i=8 * this is InterA.pA1: ia=9,InterObj.i=8 * this is InterC.pC: ic=6 * this is InterA.pA: ia=9,InterObj.i=8 * this is InterA.pA1: ia=9,InterObj.i=8 * this is InterC.pC: ic=6 * TestInterface.noName */ public static void main(String[] args) { InterObj io=new InterObj(); io.p(); } } /* * 用于創建內部類的接口 */ interface TestInterface{ public void pppp(); } /* * 用于測試局部內部類的局部變量類 */ class Test{ private int t= 9 ; public int getT(){ return t; } public void setT( int t1){ t=t1; } } |
再分享一則實例:
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
|
public class InnerClass { static Toy toy = new Toy(){ String name = "老吳" ; @Override public void jump() { System.out.println(name+ "跳出地球" ); go(); } public void go(){ System.out.println( "奔跑" ); } } ; /*內部類:定義在類的內部的類 *1.成員內部類: *1.1成員內部類可以直接訪問外部類的屬性 *1.2通過 外部類名.this 這種方式訪問外部類的當前對象 *成員內部類實例化對象: 外部類名.內部類名 引用名 = 外部類對象.new 內部類名(); *2.靜態內部類 *2.1靜態內部類內部不能訪問外部類的成員資源,只能通過類名訪問外部類的靜態資源 *靜態內部類實例化對象: 外部類名.內部類名 引用名 = new 外部類名.內部類名(); *3.局部內部類: *3.1也可以直接訪問外部類的屬性 *3.2也可以通過 外部類名.this 訪問外部類當前對象 *3.3局部內部類只能在方法內部被訪問,修飾符只能是默認的 *4.匿名內部類:在需要一個類的具體子類實例的時候,臨時的生成一個類使用 *new 類名(){ * 重寫方法; *}; *4.1匿名內部類訪問外部方法的屬性,該屬性會被轉換為常量 *4.2匿名內部類中新增的屬性和方法,只能在匿名內部類內部使用 * */ public static void main(String[] args) { Person per = new Person("老陳",18); Person.Computer pc = per.new Computer("外星人"); Person.Computer pc1 = new Person("簡自豪",18).new Computer("外星人"); pc.runGame(); pc1.runGame(); Person.Computer1 pc11 = new Person.Computer1("網吧的電腦"); pc11.runGame(); per.useComputer(); String str = "啦啦啦"; //str = "羅庫偶偶"; Computer com = new Computer(){ @Override public void runGame() { // TODO Auto-generated method stub System.out.println(per.age+"歲的"+per.name+"在玩啦啦啦啦啦德瑪西塔"); System.out.println(str); } } ; com.runGame(); //具體類的匿名內部類獨享 /*Toy toy = new Toy(){ @Override public void jump() { System.out.println("跳出地球"); } };*/ toy.jump(); toy.jump(); //toy.go(); //System.out.println(toy.); } } class Person { String name; int age; static int age1 = 18 ; static String name1 = "全職高手" ; public Person(String name, int age) { super (); this .name = name; this .age = age; } public void playGame(){ System.out.println(name+ "玩游戲" ); } public class Computer{ String name; public Computer(String name) { super (); this .name = name; } public void runGame(){ System.out.println(name+ "運行游戲" ); System.out.println(age+ "歲的" +Person. this .name+ "玩游戲" ); } } public static class Computer1{ String name; public Computer1(String name) { super (); this .name = name; } public void runGame(){ System.out.println(name+ "運行游戲" ); System.out.println(Person.age1+ "的" +Person.name1+ "在玩游戲" ); } } public void useComputer(){ class Computer{ String name; public Computer(String name) { super (); this .name = name; } public void runGame(){ System.out.println(name+ "運行游戲" ); System.out.println(Person. this .age+ "的" +Person. this .name+ "正在玩游戲" ); } } Computer com = new Computer( "筆記本" ); com.runGame(); } } public interface Computer { void runGame(); } public class Toy { public void jump(){ System.out.println( "玩具跳一下" ); } } |
總結
以上就是本文關于java內部測試類代碼詳解的全部內容,希望對大家有所幫助。感興趣的朋友可以繼續參閱本站其他相關專題,如有不足之處,歡迎留言指出。感謝朋友們對本站的支持!
原文鏈接:http://blog.csdn.net/wanghuiwei888/article/details/78797620