內部類
內部類(inner class) 是定義在另一個類中的類。使用原因如下:
1.內部類方法可以訪問該類定義所在的作用域中的數據, 包括私有的數據。
2.內部類可以對同一個包中的其他類隱藏起來。
3.當想要定義一個回調函數且不想編寫大量代碼時,使用匿名 (anonymous) 內部類比較便捷。
使用內部類訪問對象狀態
public class TalkingClock
{
private int interval:
private boolean beep;
public TalkingClock(int interval, boolean beep) { . . . }
public void start() { • . . }
public class TimePrinter implements ActionListener
// an inner class
{
public void actionPerformed(ActionEvent event) {
System.out.println("At the tone, the time is " + new Oate();)
if (beep) Toolkit.getDefaultToolkit().beep();
}
}
}
內部類既可以訪問自身的數據域,也可以訪問創建它的外圍類對象的數據域。爲了能夠運行這個程序, 內部類的對象總有一個隱式引用, 它指向了創建它的外部類對象。
TimePrinter 類聲明爲私有的。這樣一來, 只有 TalkingClock 的方法才能夠構造TimePrinter 對象。只有內部類可以是私有類,而常規類只可以具有包可見性,或公有可見性。
內部類的特殊語法規則
使用外圍類引用的表達式
OuterClass.this
內部對象的構造器:
outerObject.new InnerClass (construction parameters)
最新構造的 TimePrinter 對象的外圍類引用被設置爲創建內部類對象的方法中的this 引用。這是一種最常見的情況。通常,this 限定詞是多餘的。不過,可以通過顯式地命名將外圍類引用設置爲其他的對象。
TalkingClock jabberer = new TalkingClock(1000, true);
TalkingOock.TimePrinter listener = jabberer.new TimePrinter();
在外圍類的作用域之外,可以這樣引用內部類:
OuterClass.InnerClass
局部內部類
可以在一個方法中定義局部類
public void start() {
class TimePrinter inpleients ActionListener
{
public void actionPerformed(ActionEvent event) {
System.out.println("At the tone, the tine is " + new Date());
if (beep) Toolkit.getDefaultToolkit.beep():
}
}
ActionListener listener = new TimePrinter();
Timer t = new Timer(interval, listener);
t.start();
}
局部類不能用 public 或 private 訪問說明符進行聲明。它的作用域被限定在聲明這個局部類的塊中。
局部類有一個優勢, 即對外部世界可以完全地隱藏起來。 即使 TalkingClock 類中的其他代碼也不能訪問它。除 start 方法之外, 沒有任何方法知道 TimePrinter 類的存在。
匿名內部類
將局部內部類的使用再深人一步。 假如只創建這個類的一個對象,就不必命名了。這種類被稱爲匿名內部類(anonymous inner class)。
public void start(int interval, boolean beep) {
ActionListener listener = new ActionListenerO
{
public void actionPerformed(ActionEvent event) {
System.out.println("At the tone, the time is " + new Date());
if (beep) Toolkit.getDefaultToolkit().beep();
}
};
Timer t = new Timer(interval, listener);
t.start();
}
多年來,Java 程序員習慣的做法是用匿名內部類實現事件監聽器和其他回調。如今最好還是使用 lambda 表達式。
public void start(int interval, boolean beep) {
Timer t = new Timer(interval, event -> {
Systea.out.printlnC'At the tone, the time is " + new Date());
if (beep) Toolkit.getDefaultToolkit().beep();
});
t.start();
}
下面的技巧稱爲“ 雙括號初始化” (double brace initialization), 這裏利用了內部類語法。假設你想構造一個數組列表,並將它傳遞到一個方法:
ArrayList<String> friends = new ArrayList<>();
friends,add("Harry");
friends,add("Tony");
invite(friends);
如果不再需要這個數組列表,最好讓它作爲一個匿名列表。
invite(new ArrayList<String>() {{ add("Harry"); add("Tony"); }});
注意這裏的雙括號。外層括號建立了 ArrayList 的一個匿名子類。內層括號則是一個對象構造塊
靜態內部類
有時候, 使用內部類只是爲了把一個類隱藏在另外一個類的內部,並不需要內部類引用外圍類對象。爲此,可以將內部類聲明爲 static, 以便取消產生的引用。
靜態內部類的對象除了沒有對生成它的外圍類對象的引用特權外, 與其他所冇內部類完全一樣。
class ArrayAlg{
...
public static class Pair{
...
}
}