16
16
17
17
先來介紹成員內部類別,基本上是在一個類別中直接宣告另一個類別,例如:
18
18
19
+ ``` java
19
20
public class OuterClass {
20
21
// 內部類別
21
22
private class InnerClass {
22
23
// ....
23
24
}
24
25
}
26
+ ```
25
27
26
28
成員內部類別同樣也可以使用 "public"、"protected" 或 "private" 來修飾其存取權限,範例 9.1 簡單示範成員內部類別的使用。
27
29
@@ -91,12 +93,14 @@ public class PointShow {
91
93
92
94
內部類別還可以被宣告為 "static",不過由於是 "static",它不能存取外部類別的方法,而必須透過外部類別所生成的物件來進行呼叫,被宣告為 static的內部類別,事實上也可以看作是另一種名稱空間的管理方式,例如:
93
95
96
+ ``` java
94
97
public class Outer {
95
98
public static class Inner {
96
99
....
97
100
}
98
101
....
99
102
}
103
+ ```
100
104
101
105
您可以如以下的方式來使用 Inner 類別:
102
106
@@ -110,9 +114,11 @@ public class PointShow {
110
114
111
115
內部匿名類別可以不宣告類別名稱,而使用 "new" 直接產生一個物件,內部匿名類別可以是繼承某個類別或是實作某個介面,內部匿名類別的宣告方式如下:
112
116
117
+ ``` java
113
118
new [類別或介面()] {
114
119
// 實作
115
120
}
121
+ ```
116
122
117
123
一個使用內部匿名類別的例子如範例7.3所示,您直接繼承 Object 類別定義一個匿名類別,重新定義 toString() 方法,並使用匿名類別直接產生一個物件。
118
124
@@ -138,6 +144,7 @@ public class AnonymousClassDemo {
138
144
139
145
注意如果要在內部匿名類別中使用外部的區域變數,變數在宣告時必須為 "final",例如下面的陳述是無法通過編譯的:
140
146
147
+ ``` java
141
148
....
142
149
public void someMethod() {
143
150
int x = 10 ; // 沒有宣告final
@@ -150,13 +157,15 @@ public class AnonymousClassDemo {
150
157
System . out. println(obj);
151
158
}
152
159
....
160
+ ```
153
161
154
162
在進行編譯時,編譯器會回報以下的錯誤:
155
163
156
164
local variable x is accessed from within inner class; needs to be declared final
157
165
158
166
您要在宣告區域變數x時加上"final"才可以通過編譯:
159
167
168
+ ``` java
160
169
....
161
170
public void someMethod() {
162
171
final int x = 10 ; // 宣告final
@@ -169,6 +178,7 @@ public class AnonymousClassDemo {
169
178
System . out. println(obj);
170
179
}
171
180
....
181
+ ```
172
182
173
183
為什麼要加上 "final" 宣告呢?原因在於區域變數 x 並不是真正被拿來於內部匿名類別中使用,x 會被匿名類別複製作為資料成員來使用,由於真正在匿名類別中的x是複製品,即使您在內部匿名類別中對 x 作了修改(例如 x=10 的指定),也不會影響真正的區域變數x,事實上您也通不過編譯器的檢查,因為編譯器會要求您加上 "final" 關鍵字,這樣您就知道不能在內部匿名類別中改變 x 的值,因為即使能改變也沒有意義。
174
184
@@ -359,56 +369,69 @@ public class Point2DDemo3 {
359
369
360
370
類別上的權限設定會約束類別成員上的權限設定,所以如果類別上不宣告 "public",而類別成員上設定了 "public",則類別成員同樣的也只能被同一個套件的類別存取,也就是說如果您這麼撰寫程式:
361
371
372
+ ``` java
362
373
package onlyfun.caterpillar ;
363
374
class SomeClass {
364
375
// ...
365
376
public void someMethod () {
366
377
// ....
367
378
}
368
379
}
380
+ ```
369
381
370
382
其效果等同於:
371
383
384
+ ``` java
372
385
package onlyfun.caterpillar ;
373
386
class SomeClass {
374
387
// ...
375
388
void someMethod () {
376
389
// ....
377
390
}
378
391
}
392
+ ```
379
393
380
394
由這邊的討論,可以再來看看預設建構方法的權限。首先要知道的是,當您在 Java 中定義一個類別,但沒有定義建構方法時,編譯器會自動幫您產生一個預設建構方法,也就是說,如果您這麼寫:
381
395
396
+ ``` java
382
397
package onlyfun.caterpillar ;
383
398
public class Test {
384
399
....
385
400
}
401
+ ```
386
402
387
403
則編譯器會自動加上預設建構方法,也就是相當於這麼寫:
388
404
405
+ ``` java
389
406
package onlyfun.caterpillar ;
390
407
public class Test {
391
408
public Test () {
392
409
}
393
410
....
394
411
}
412
+ ```
395
413
396
414
如果您自行定義建構方法,則編譯器就不會幫您加上預設建構方法,所以當您這麼定義時:
397
415
416
+ ``` java
398
417
package onlyfun.caterpillar ;
399
418
public class Test {
400
419
public Test (int i ) {
401
420
...
402
421
}
403
422
....
404
423
}
424
+ ```
405
425
406
426
則在建構時,就必須指明使用哪個建構方法,簡單的說,您就不能使用以下的方式來建構:
407
427
428
+ ``` java
408
429
Test test = new Test ();
430
+ ```
409
431
410
432
有時會建議即使沒有用到,在定義自己的建構方法的同時,也加上個沒有參數的建構方法,例如:
411
433
434
+ ``` java
412
435
package onlyfun.caterpillar ;
413
436
public class Test {
414
437
public Test () { // 即使沒用到,也先建立一個空的建構方法
@@ -419,28 +442,35 @@ public class Point2DDemo3 {
419
442
}
420
443
....
421
444
}
445
+ ```
422
446
423
447
要注意的是,在繼承時,如果您沒有使用 super() 指定要使用父類別的哪個建構方法,則預設會尋找父類別中無參數的建構方法。
424
448
425
449
預設建構方法的存取權限是跟隨著類別的存取權限而設定,例如:
426
450
451
+ ``` java
427
452
package onlyfun.caterpillar ;
428
453
public class Test {
429
454
}
455
+ ```
430
456
431
457
由於類別宣告為 public,所以預設建構方法存取權限為 public。如果是以下的話:
432
458
459
+ ``` java
433
460
package onlyfun.caterpillar ;
434
461
class Test {
435
462
}
463
+ ```
436
464
437
465
則預設建構方法存取權限為套件存取權限,也就是編譯器會自動為您擴展為:
438
466
467
+ ``` java
439
468
package onlyfun.caterpillar ;
440
469
class Test {
441
470
Test () {
442
471
}
443
472
}
473
+ ```
444
474
445
475
在這邊整理一下 private、protected、public 與 default 與類別及套件的存取關係:
446
476
@@ -515,15 +545,18 @@ public class ImportStaticDemo {
515
545
516
546
如果編譯器無法判斷,則會回報錯誤,例如若您定義了如下的類別:
517
547
548
+ ``` java
518
549
package onlyfun.caterpillar ;
519
550
public class Arrays {
520
551
public static void sort (int [] arr ) {
521
552
// ....
522
553
}
523
554
}
555
+ ```
524
556
525
557
然後如下撰寫程式:
526
558
559
+ ``` java
527
560
import static java.lang.System.out ;
528
561
import static java.util.Arrays.sort ;
529
562
import static onlyfun.caterpillar.Arrays.sort ;
@@ -536,6 +569,7 @@ public class ImportStaticDemo {
536
569
}
537
570
}
538
571
}
572
+ ```
539
573
540
574
由於從 java.util.Arrays.sort 與 onlyfun.caterpillar.Arrays.sort 的兩行 "import static" 上都可以找到 sort,編譯器無法辦別要使用哪一個 sort() 方法,因而編譯時會出現以下的錯誤:
541
575
0 commit comments