簡潔明瞭:Java的匿名內部類

一 點睛

匿名內部類適合創建那種只需要一次使用的類,定義匿名內部類的語法格式如下:

new 父類構造器(實參列表) | 實現接口()

{

      //匿名內部類的類體部分

}

從上面的定義可以看出,匿名內部類必須繼承一個父類,或實現一個接口,但最多隻能繼承一個父類,或實現一個接口。

兩條規則。

  • 匿名內部類不能是抽象類。

  • 匿名內部類不能定義構造器。由於匿名內部類沒有類名,所以無法定義構造器,但匿名內部類可以初始化塊,可以通過初始化塊來完成構造器需要完成的工作。

二 實戰

1 點睛

最常用的創建匿名內部類的方式是創建某個接口類型的對象。

2 代碼

interface Product
{
   public double getPrice();
   public String getName();
}
public class AnonymousTest
{
   public void test(Product p)
   {
      System.out.println("購買了一個" + p.getName()
         + ",花掉了" + p.getPrice());
   }
   public static void main(String[] args)
   {
      AnonymousTest ta = new AnonymousTest();
      // 調用test()方法時,需要傳入一個Product參數,
      // 此處傳入其匿名內部類的實例
      ta.test(new Product()
      {
         public double getPrice()
         {
            return 567.8;
         }
         public String getName()
         {
            return "AGP顯卡";
         }
      });
   }
}

3 運行

<p>購買了一個AGP顯卡,花掉了567.8</p>

4 說明

定義匿名內部類無須class關鍵字,而是在定義匿名內部類時直接生成該匿名內部類的對象。

由於匿名內部類不能是抽象類,所以匿名內部類必須實現它的抽象父類或接口裏包含的所有抽象方法。

三 實戰

1 點睛

當通過接口來創建匿名內部類時,匿名內部類不能顯示創建構造器,因此匿名內部類裏只有一個隱式的無參構造器,故new接口名後的括號裏不能傳入參數值。

如果通過繼承父類來創建匿名內部類時,匿名內部類將擁有和父類相似的構造器,此處的相似指的是擁有相同的形參列表。

2 代碼

abstract class Device
{
   private String name;
   public abstract double getPrice();
   public Device(){}
   public Device(String name)
   {
      this.name = name;
   }
   // 此處省略了name的setter和getter方法
   public void setName(String name)
   {
      this.name = name;
   }
   public String getName()
   {
      return this.name;
   }
}
public class AnonymousInner
{
   public void test(Device d)
   {
      System.out.println("購買了一個" + d.getName()
         + ",花掉了" + d.getPrice());
   }
   public static void main(String[] args)
   {
      AnonymousInner ai = new AnonymousInner();
      // 調用有參數的構造器創建Device匿名實現類的對象
      ai.test(new Device("電子示波器")
      {
         public double getPrice()
         {
            return 67.8;
         }
      });
      // 調用無參數的構造器創建Device匿名實現類的對象
      Device d = new Device()
      {
         // 初始化塊
         {
            System.out.println("匿名內部類的初始化塊...");
         }
         // 實現抽象方法
         public double getPrice()
         {
            return 56.2;
         }
         // 重寫父類的實例方法
         public String getName()
         {
            return "鍵盤";
         }
      };
      ai.test(d);
   }
}

3 運行

購買了一個電子示波器,花掉了67.8
匿名內部類的初始化塊...
購買了一個鍵盤,花掉了56.2

當創建以Device爲父類的匿名內部類時,既可以傳入參數,代表調用父類帶參數的構造器;也可以不傳入參數,代表調用父類無參數的構造器。

當創建匿名內部類時,必須實現接口或抽象父類裏的所有抽象方法。如果有需要,也可以重寫父類中的普通方法。

四 實戰

1 點睛

在Java 8之前,Java要求被局部內部類、匿名內部類訪問的局部變量必須使用final修飾,從Java 8開始這個限制取消了,Java 8更加智能:如果局部變量被匿名內部類訪問,那麼該局部變量相對於自動使用了final修飾。

2 代碼

interface A
{
   void test();
}
public class ATest
{
   public static void main(String[] args)
   {
      int age = 8;     // ①
      // 下面代碼將會導致編譯錯誤
      // 由於age局部變量被匿名內部類訪問了,因此age相當於被final修飾了
      //age = 2;
      A a = new A()
      {
         public void test()
         {
            // 在Java 8以前下面語句將提示錯誤:age必須使用final修飾
            // 從Java 8開始,匿名內部類、局部內部類允許訪問非final的局部變量
            System.out.println(age);
         }
      };
      a.test();
   }
}

3 結果

<p>
8</p>

4 說明

Java 8將這個功能稱爲“effectively final”,它的意思是對於被匿名內部類訪問的局部變量,可以用final修飾,也可以不用final修飾,但必須按照有final修飾的方式來使用——也就是一次賦值後,以後不能重新賦值。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章