Java 面向物件:內部類
禁止碼迷,布布扣,豌豆代理,碼農教程,愛碼網等第三方爬蟲網站爬取!
目錄
內部類
內部類是定義在另一個類中的類,例如 TalkingClock 類中內嵌了 TimePrinter 類:
class TalkingClock{ private int interval; private boolean beep; public TalkingClock(int interval, boolean beep){} public void start(){} public class TimePrinter implements ActionListener{ public void actionPerformed(ActionEvent event){} } }
內部類可以對同一個包中的其他類隱藏細節,同時內部類中的方法可以訪問原來的類中的作用域資料。
訪問外部物件
內部類可以訪問自身的資料欄位,也可以訪問建立它的外圍類物件的資料欄位。內部類會有一個隱式引用,指向建立它的外部類物件。
對外圍類的引用在構造器中設定,編譯器會修改所有內部類的構造器,新增一個對外部類引用的引數。使用外部類引用的語法為:
OuterClass.this
例如內部類 TimePrinter 引用外部類 TalkingClock 的 beep 引數,嚴格來說要寫成這樣。
TalkingClock.this.beep
訪問內部物件
使用內部類的構造器時,可以使用下面的語法來實現:
outerObject.new InnerClass(construction parameters)
在外部類的作用域之外,想要引用內部類就需要用下面的語法:
OuterClass.InnerClass
區域性內部類
區域性內部類類似方法的區域性變數,在類外或者類的其他方法中不能訪問這個內部類。通常情況下可以在某個方法中區域性實現一個類,這個類將用於輔助該方法的功能實現。例如:
public void start(){ class TimePrinter implements ActionListener{ public void actionPerformed(ActionEvent event){ System.out.println("The time is " + Instant.ofEpochMilli(event.getWhen())); if (beep) { Toolkit.getDefaultToolkit().beep(); } } } TimePrinter listener = new TimePrinter(); TalkingClock timer = new Timer(interval, listener); timer.start(); }
宣告區域性類時不能有訪問說明符,區域性類的作用域被限定在了這個區域性類塊中。區域性類可以做到對外界的絕對隱藏,這是個很大的優勢。
區域性類還有個優點,就是可以訪問區域性變數。當局部變數傳參進來時,區域性變數也會被傳入構造器,此時編譯器會為區域性變數提供相應的例項欄位,儲存一個副本。這麼做的好處是,當函式呼叫結束導致區域性變數消失時,區域性類還能夠使用這個區域性變數。例如將上述的 start 方法改為傳入 2 個引數,仍然不影響正常使用。
public void start(int interval, boolean beep)
匿名內部類
使用區域性類時,如果只是想建立這個區域性類的一個物件,甚至不需要給出這個類的名字,這種類就成為匿名內部類。匿名內部類的語法為:
new SuperType(construction parameters){
inner class methods and data
}
new InterfaceType(){
methods and data
}
SuperType 指的是超類,此時區域性類就需要拓展這個類。匿名區域性類可以基於介面建立,此時區域性類就要實現這個介面。由於構造器的名字必須和類名相同,而匿名區域性類沒有類名,因此匿名區域性類不能有構造器,此時如果要構造引數就需要傳遞給超類的構造器。例如將上述的區域性類改造成匿名內部類:
public void start(){
var listener = new ActionListener(){
public void actionPerformed(ActionEvent event){
System.out.println("The time is " + Instant.ofEpochMilli(event.getWhen()));
if (beep) {
Toolkit.getDefaultToolkit().beep();
}
}
}
TalkingClock timer = new Timer(interval, listener);
timer.start();
}
靜態內部類
有時候使用內部類只是想隱藏一個類,並不需要內部類有外部類的引用,因此可以用 static 關鍵字宣告靜態內部類。例如定義 ArrayAlg 類中實現 minmax 方法,minmax 方法的功能是同時返回一個數組的最大值和最小值,但是用 return 只能返回一個值。因此可以定義一個靜態內部類 Pair,Pair 類有兩個引數可以分別儲存最大和最小值,這樣就可以通過返回 Pair 方法同時返回 2 個值了。
class ArrayAlg{
public static class Pair{
private double first;
private double second;
public Pair(double f, double s){
first = f;
second = s;
}
public double getFirst() { return first; }
public double getSecond() { return second; }
}
public static Pair minmax(double[] values){
double min = Double.POSITIVE_INFINITY;
double max = Double.NEGATIVE_INFINITY;
for (double v : values){
if (min > v) min = v;
if (max < v) max = v;
}
return new Pair(min, max);
}
}
只要內部類不需要訪問外圍類物件,就應該宣告為靜態內部類。和其他內部類不同,靜態內部類可以有靜態欄位和方法。
參考資料
《Java 核心技術 卷Ⅰ》,[美]Cay S.Horstmann 著,林琪 蘇鈺涵 等譯,機械工業出版社