匿名內部類和示例 - 1

“嗨,阿米戈!”

“但我們已經打過招呼了,艾莉!”

“餵,你別跟你阿姨吵架,在31世紀,半個小時以上沒見人,再打聲招呼是習慣性的,所以你別給我態度!”

“總之,又到了另一個有趣的話題了:機器人繁殖!”

“噢噢。”

“開玩笑的,新話題是匿名內部類。”

“在 Java 中,有時會出現需要一個類繼承多個類的情況。由於 Java 不支持多重繼承,他們使用內部類解決了這個問題:在我們的類中,我們聲明一個內部類並使它繼承了我們需要它繼承的任何類。這是一個例子:“

繼承 Thread 類的內部類示例
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對象。

換句話說,我們寫了一大堆代碼只是為了覆蓋一個方法並創建一個對象。

您還記得我是如何談論構造函數的發明的嗎?

在構造函數之前 在構造函數之後
TigerThread thread = new TigerThread();

private class TigerThread extends Thread
{
 public void run()
 {
  tigerRun();
 }
}
Thread thread = new Thread()
{
 public void run()
 {
  tigerRun();
 }
};

“我看到代碼變得更加緊湊,但我不太明白髮生了什麼。”

“我們可以將四件事合而為一:”

1)派生類的聲明

2)方法覆蓋

3)變量的聲明

4) 創建派生類的實例。

“事實上,我們正​​在做的是結合兩個操作:聲明派生類和創建該類的實例。”

沒有匿名類 使用匿名類
Cat tiger = new Tiger();

class Tiger extends Cat
{
}
Cat tiger = new Cat()
{
};

“讓我們再次探討語法:”

線程變量的聲明
Thread thread = new Thread();
聲明類型為“繼承 Thread 的匿名類”的變量
Thread thread = new Thread()
{

};

“請注意,我們不是簡單地定義一個新類。我們正在創建一個變量——末尾有一個分號!”

“如果我們想覆蓋運行方法,那麼我們需要這樣寫:”

線程變量的聲明
Thread thread = new Thread()
{
 public void run()
  {
   System.out.println("new run-method");
  }
};

“你很快就明白了。幹得好!”

“謝謝。如果我們需要其他不屬於 Thread 類的方法怎麼辦?”

“你可以寫。”

“雖然是匿名的,但這是一個成熟的內部類:”

Java代碼 描述
Thread thread = new Thread()
{
  public void run()
  {
   printHi();
  }

  public void printHi()
  {
   System.out.println("Hi!");
  }
};
紅色:創建變量的代碼。

綠色:創建對象的代碼。

藍色:匿名派生類的代碼。

“一個完整的內部類?”

“所以我可以使用外部類的變量?”

“絕對地。”

“我可以將一些東西傳遞給構造函數嗎?”

“是的,但只有超類構造函數的參數:”

班級 匿名內部類的實例
class Cat
{
 int x, y;
 Cat(int x, int y)
 {
  this.x = x;
  thix.y = y;
 }
}
Cat cat = new Cat(3,4)
{
  public void print()
  {
   System.out.println(x+" "+y);
  }
};

“我們不能將自己的參數添加到別人的構造函數中。但是我們可以使用外部類的變量,這很好地彌補了這個缺點。”

“如果我真的還需要向構造函數添加其他參數怎麼辦?”

“然後聲明一個普通的(非匿名的)內部類並使用它。”

“對了,我差點忘記了。”

“如果我聲明一個靜態變量怎麼辦?這會使匿名類成為靜態嵌套類而不是內部類嗎?換句話說,它會不會缺少對外部類的引用?”

“不。這將是一個匿名內部類。看看這些例子。”

使用匿名類 沒有匿名類
Thread thread = new Thread()
{
  public void run()
  {
   tigerRun();
  }
};
TigerThread thread = new TigerThread();

private class TigerThread extends Thread
{
 public void run()
 {
  tigerRun();
 }
}
static Thread thread = new Thread()
{
  public void run()
  {
   tigerRun();
  }
};
static TigerThread thread = new TigerThread();

private class TigerThread extends Thread
{
 public void run()
 {
  tigerRun();
 }
}

“我明白了。只有靜態變量是靜態的,類不是。”

“是的。”

“事實上,編譯器會為所有匿名內部類創建內部類。這些類通常被命名為 «1»、«2»、«3» 等。”