“嗨,阿米戈!”
“但我們已經打過招呼了,艾莉!”
“餵,你別跟你阿姨吵架,在31世紀,半個小時以上沒見人,再打聲招呼是習慣性的,所以你別給我態度!”
“總之,又到了另一個有趣的話題了:機器人繁殖!”
“噢噢。”
“開玩笑的,新話題是匿名內部類。”
“在 Java 中,有時會出現需要一個類繼承多個類的情況。由於 Java 不支持多重繼承,他們使用內部類解決了這個問題:在我們的類中,我們聲明一個內部類並使它繼承了我們需要它繼承的任何類。這是一個例子:“
class Tiger extends Cat
{
public void tigerRun()
{
.....
}
public void startTiger()
{
TigerThread thread = new TigerThread();
thread.start();
}
class TigerThread extends Thread
{
public void run()
{
tigerRun();
}
}
}
“讓我們深入研究另一個例子:”
我們需要 Thread 類的子類來覆蓋它的 run 方法。”
“這就是為什麼我們在 Tiger 類中聲明了 TigerThread內部類,它繼承了 Thread 並重寫了 run 方法。
“為方便起見,我們在 Tiger 類中定義了兩個方法:tigerRun 和 startTiger(類似於 Thread 的運行和啟動方法。”
“在 tigerStart 方法中,我們創建了一個TigerThread對象並調用它的 start() 方法。”
“JVM 將創建一個新線程,該線程將在調用TigerThread 的run 方法時開始運行。”
“這個方法然後調用我們的運行方法:tigerRun。”
“我以前使用過線程,所以這看起來很簡單。”
“我們必須將方法命名為 tigerRun 和 tigerStart 嗎?”
“不,我們可以稱它們為 run 和 start,但我也想證明我們沒有繼承 Thread。解釋可能更令人困惑。”
“好的。那麼我想我明白了。但是如果第二次調用 tigerStart,我們將創建並啟動第二個 Thread 對象。這是否意味著我們將擁有 «一隻老虎在兩個不同的線程上運行»? “
“好吧,你不是很敏銳嗎!你是對的,那可不好。讓我們像這樣重寫代碼:”
class Tiger extends Cat
{
public void tigerRun()
{
.....
}
public void startTiger()
{
thread.start();
}
private TigerThread thread = new TigerThread();
private class TigerThread extends Thread
{
public void run()
{
tigerRun();
}
}
}
“它還不夠完美。你仍然不能調用這樣的方法兩次。但這一次,至少我們不會創建第二個線程,讓一切看起來都很好。”
“沒錯,Tiger第二次啟動,你會得到一個異常。”
“我已經比你更善於發現錯誤了,艾莉!”
“是啊,你做得很好。那讓我們繼續匿名內部類。”
“請注意上面代碼的幾個方面:”
1)我們繼承了 Thread 類,但實際上沒有實現任何代碼。“更多的是 «我們必須繼承 Thread 類»,而不是 «我們繼承它是為了擴展它»。
2)只會創建一個TigerThread對象。
換句話說,我們寫了一大堆代碼只是為了覆蓋一個方法並創建一個對象。
您還記得我是如何談論構造函數的發明的嗎?
在構造函數之前 | 在構造函數之後 |
---|---|
|
|
“我看到代碼變得更加緊湊,但我不太明白髮生了什麼。”
“我們可以將四件事合而為一:”
1)派生類的聲明
2)方法覆蓋
3)變量的聲明
4) 創建派生類的實例。
“事實上,我們正在做的是結合兩個操作:聲明派生類和創建該類的實例。”
沒有匿名類 | 使用匿名類 |
---|---|
|
|
“讓我們再次探討語法:”
Thread thread = new Thread();
Thread thread = new Thread()
{
};
“請注意,我們不是簡單地定義一個新類。我們正在創建一個變量——末尾有一個分號!”
“如果我們想覆蓋運行方法,那麼我們需要這樣寫:”
Thread thread = new Thread()
{
public void run()
{
System.out.println("new run-method");
}
};
“你很快就明白了。幹得好!”
“謝謝。如果我們需要其他不屬於 Thread 類的方法怎麼辦?”
“你可以寫。”
“雖然是匿名的,但這是一個成熟的內部類:”
Java代碼 | 描述 |
---|---|
|
紅色:創建變量的代碼。
綠色:創建對象的代碼。 藍色:匿名派生類的代碼。 |
“一個完整的內部類?”
“所以我可以使用外部類的變量?”
“絕對地。”
“我可以將一些東西傳遞給構造函數嗎?”
“是的,但只有超類構造函數的參數:”
班級 | 匿名內部類的實例 |
---|---|
|
|
“我們不能將自己的參數添加到別人的構造函數中。但是我們可以使用外部類的變量,這很好地彌補了這個缺點。”
“如果我真的還需要向構造函數添加其他參數怎麼辦?”
“然後聲明一個普通的(非匿名的)內部類並使用它。”
“對了,我差點忘記了。”
“如果我聲明一個靜態變量怎麼辦?這會使匿名類成為靜態嵌套類而不是內部類嗎?換句話說,它會不會缺少對外部類的引用?”
“不。這將是一個匿名內部類。看看這些例子。”
使用匿名類 | 沒有匿名類 |
---|---|
|
|
|
|
“我明白了。只有靜態變量是靜態的,類不是。”
“是的。”
“事實上,編譯器會為所有匿名內部類創建內部類。這些類通常被命名為 «1»、«2»、«3» 等。”
GO TO FULL VERSION