John Squirrels
等級 41
San Francisco

匿名類

在 Toto sisi 群組發布
你好!在今天的課程中,我們將繼續研究嵌套類的主題。現在是最後一組的時候了:匿名內部類。讓我們回到我們的圖表: 匿名類 - 2就像我們上節課講到的本地類一樣,匿名類是內部類的一種……它們也有一些相同點和不同點。但首先,讓我們深入探討:為什麼他們被稱為“匿名”?要回答這個問題,請考慮一個簡單的例子。想像一下,我們有一個不斷運行並做某事的基本程序。我們想為這個程序創建一個監控系統,由幾個模塊組成。一個模塊將跟踪性能的一般指標並維護日誌。第二個將在錯誤日誌中註冊和記錄錯誤。第三個將跟踪可疑活動:例如,未經授權的訪問嘗試和其他與安全相關的事情。因為從本質上講,所有三個模塊都應該簡單地從程序的開頭開始並在後台運行,

public interface MonitoringSystem {
  
   public void startMonitoring();
}
3個具體類將實現它:

public class GeneralIndicatorMonitoringModule implements MonitoringSystem {
   
@Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
}


public class ErrorMonitoringModule implements MonitoringSystem {

   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor errors!");
   }
}


public class SecurityModule implements MonitoringSystem {

   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor security!");
   }
}
似乎一切都井井有條。我們有一個由幾個模塊組成的非常連貫的系統。他們每個人都有自己的行為。如果我們需要新模塊,我們可以添加它們,因為我們有一個很容易實現的接口。但是讓我們考慮一下我們的監控系統將如何工作。 匿名類 - 3基本上,我們只需要創建 3 個對象 — GeneralIndicatorMonitoringModule, ErrorMonitoringModule, SecurityModule— 並startMonitoring()在每個對像上調用方法。也就是說,我們需要做的就是創建 3 個對象並調用它們的 1 個方法。

public class Main {

   public static void main(String[] args) {

       GeneralIndicatorMonitoringModule generalModule = new GeneralIndicatorMonitoringModule();
       ErrorMonitoringModule errorModule = new ErrorMonitoringModule();
       SecurityModule securityModule = new SecurityModule();

       generalModule.startMonitoring();
       errorModule.startMonitoring();
       securityModule.startMonitoring();
   }
}
控制台輸出:

Starting to monitor general indicators! 
Starting to monitor errors! 
Starting to monitor security!
通過如此少的工作,我們已經編寫了整個系統:3 個類和一個接口!而這一切只需要6行代碼就可以實現。另一方面,我們有什麼選擇?好吧,我們編寫這些“一次性”課程並不是很酷。但是我們怎樣才能解決這個問題呢?在這裡匿名內部類來拯救我們!在我們的案例中,它們是這樣的:

public class Main {

   public static void main(String[] args) {

       MonitoringSystem generalModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor general indicators!");
           }
       };

       

MonitoringSystem errorModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor errors!");
           }
       };

       MonitoringSystem securityModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor security!");
           }
       };

       generalModule.startMonitoring();
       errorModule.startMonitoring();
       securityModule.startMonitoring();
   }
}
讓我們弄清楚發生了什麼!看起來我們正在創建一個接口對象:

MonitoringSystem generalModule = new MonitoringSystem() {
   
@Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
};
但是我們早就知道不能創建界面對象了!所以它是——這是不可能的。事實上,這不是我們正在做的。當我們寫:

MonitoringSystem generalModule = new MonitoringSystem() {
   
};
Java 機器內部發生以下情況:
  1. 創建一個未命名的 Java 類來實現該MonitoringSystem接口。
  2. 當編譯器看到這樣的類時,它要求你實現接口的所有方法MonitoringSystem(我們做了 3 次)。
  3. 創建了此類的一個對象。注意代碼:

MonitoringSystem generalModule = new MonitoringSystem() {
   
};
末尾有一個分號!它在那裡是有原因的。我們同時聲明類(使用大括號)並創建它的實例(使用();)。startMonitoring()我們的三個對像中的每一個都以自己的方式重寫該方法。最後,我們簡單地對它們中的每一個調用這個方法:

generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
控制台輸出:

Starting to monitor general indicators! 
Starting to monitor errors! 
Starting to monitor security!
就是這樣!我們實現了我們的目標:我們創建了三個MonitoringSystem對象,以三種不同的方式覆蓋了一個方法,並調用了它三次。所有三個模塊都已成功調用並正在運行。同時,我們程序的結構也變得簡單多了!畢竟,現在可以從程序中完全刪除GeneralIndicatorMonitoringModuleErrorMonitoringModule和類!SecurityModule我們根本不需要它們——沒有它們我們也做得很好。 如果我們的每個匿名類都需要一些不同的行為,例如它自己的其他人沒有的特定方法,我們可以輕鬆地添加它們:

MonitoringSystem generalModule = new MonitoringSystem() {
  
   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor general indicators!");
   }
  
   public void someSpecificMethod() {

       System.out.println("Specific method only for the first module");
   }
};
Oracle 文檔提供了一個很好的建議:“如果您只需要使用本地類一次,請使用 [匿名類]。” 匿名類是成熟的內部類。相應地,它可以訪問外部類的變量,包括靜態變量和私有變量:

public class Main {

   private static int currentErrorCount = 23;

   public static void main(String[] args) {

       MonitoringSystem errorModule = new MonitoringSystem() {
          
           @Override
           public void startMonitoring() {
               System.out.println("Starting to monitor errors!");
           }

           public int getCurrentErrorCount() {

               return currentErrorCount;
           }
       };
   }
}
它們與本地類有一些共同之處:它們僅在聲明它們的方法內可見。errorModule在上面的示例中,任何在方法之外訪問對象的嘗試都main()將失敗。匿名類從它們的“祖先”(內部類)繼承還有一個更重要的限制:匿名類不能包含靜態變量和方法。在上面的示例中,如果我們嘗試將getCurrentErrorCount()方法設為靜態,編譯器將生成錯誤:

// Error! Inner classes cannot have static declarations
public static int getCurrentErrorCount() {

   return currentErrorCount;
}
如果我們嘗試聲明一個靜態變量,我們會得到相同的結果:

MonitoringSystem errorModule = new MonitoringSystem() {

   // Error! Inner classes cannot have static declarations!
   static int staticInt = 10;

   @Override
   public void startMonitoring() {
       System.out.println("Starting to monitor errors!");
   }

};
而我們今天的課程也結束了!但是即使我們調查了最後一組嵌套類,我們還沒有完成這個話題。關於嵌套類,我們還會學到什麼?你一定會很快發現!:)
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION