JavaRush /Java Blog /Random-TW /Java 中的匿名類

Java 中的匿名類

在 Random-TW 群組發布
你好!在今天的課程中,我們將繼續討論嵌套類別的主題。輪到最後一組了——Java 中的匿名內部類別。讓我們回到我們的圖表: 匿名類別 - 2就像我們在上一講中討論的本地類別一樣,匿名類別是內部類別的子集。它們之間也有一些相似之處和不同之處。但首先,讓我們弄清楚:為什麼他們實際上被稱為「匿名」?為此,我們來看一個簡單的範例。想像一下,我們有一個不斷運作並執行某些操作的主程式。我們想為這個程式創建一個由多個模組組成的監控系統。第一個模組將監視一般效能指標並保留日誌,第二個模組將記錄錯誤並將錯誤記錄在錯誤日誌中,第三個模組將監視可疑活動:例如,未經授權的存取嘗試和其他與安全相關的事情。由於所有三個模組本質上應該在程式開頭啟動並在背景運行,因此最好為它們建立一個通用介面:
public interface MonitoringSystem {

   public void startMonitoring();
}
它將由 3 個特定類別來實現:
public class GeneralIndicatorsMonitoringModule implements MonitoringSystem {

@Override
   public void startMonitoring() {
       System.out.println("Monitoring of general indicators has started!");
   }
}


public class ErrorMonitoringModule implements MonitoringSystem {

   @Override
   public void startMonitoring() {
       System.out.println("Bug Tracking Monitoring Started!");
   }
}


public class SecurityModule implements MonitoringSystem {

   @Override
   public void startMonitoring() {
       System.out.println("Security monitoring started!");
   }
}
似乎一切都井然有序。我們有一個相當清晰的由幾個模組組成的系統。他們每個人都有自己的行為。如果我們需要新的模組,我們可以新增它們,因為我們有一個很容易實現的介面。但讓我們考慮一下我們的監控系統將如何運作。 匿名類別 - 3本質上,我們應該只創建 3 個物件 - GeneralIndicatorsMonitoringModuleErrorMonitoringModule、 - 並在每個物件上SecurityModule呼叫一個方法。startMonitoring()也就是說,您所需要做的就是建立 3 個物件並對其呼叫 1 個方法。
public class Main {

   public static void main(String[] args) {

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

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

Мониторинг общих показателей стартовал!
Мониторинг отслеживания ошибок стартовал!
Мониторинг безопасности стартовал!
對於這麼小的工作,我們寫了一整套系統:3 個類別和一個介面!而這一切都是為了6行程式碼。另一方面,我們有什麼選擇?是的,我們寫這樣的「一次性」類別並不是很酷。但我們該如何解決這個問題呢?這就是匿名內部類別為我們提供幫助的地方!在我們的例子中它們是這樣的:
public class Main {

   public static void main(String[] args) {

       MonitoringSystem generalModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Monitoring of general indicators has started!");
           }
       };



           MonitoringSystem errorModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Bug Tracking Monitoring Started!");
           }
       };

       MonitoringSystem securityModule = new MonitoringSystem() {
           @Override
           public void startMonitoring() {
               System.out.println("Security monitoring started!");
           }
       };

       generalModule.startMonitoring();
       errorModule.startMonitoring();
       securityModule.startMonitoring();
   }
}
讓我們弄清楚這是怎麼回事!看起來我們正在創建一個介面物件:
MonitoringSystem generalModule = new MonitoringSystem() {

@Override
   public void startMonitoring() {
       System.out.println("Monitoring of general indicators has started!");
   }
};
但我們很早就知道,創建介面物件是不可能的!沒錯,這是不可能的。事實上,我們並不這樣做。我們寫下的那一刻:
MonitoringSystem generalModule = new MonitoringSystem() {

};
在 Java 機器內部會發生以下情況:
  1. 建立一個未命名的 Java 類別來實作MonitoringSystem.
  2. 編譯器看到這樣一個類,就會要求你實作所有介面方法MonitoringSystem(我們這樣做了 3 次)。
  3. 創建了該類別的一個物件。注意代碼:
MonitoringSystem generalModule = new MonitoringSystem() {

};
末尾有一個分號!她站在那裡是有原因的。我們同時聲明一個類別(透過大括號)並使用創建其物件我們的三個物件中的每一個都以自己的方式(); 重寫了一個方法。startMonitoring()最後我們簡單地對每個方法呼叫這個方法:
generalModule.startMonitoring();
errorModule.startMonitoring();
securityModule.startMonitoring();
控制台輸出:

Мониторинг общих показателей стартовал!
Мониторинг отслеживания ошибок стартовал!
Мониторинг безопасности стартовал!
就這樣!我們已經完成了我們的任務:我們創建了三個對象MonitoringSystem,以三種不同的方式重新定義它,並調用它三次。所有三個模組均已成功啟動並運行。同時,我們的程式結構也變得簡單多了!GeneralIndicatorsMonitoringModule畢竟,ErrorMonitoringModule現在可以SecurityModule從程式中完全刪除課程!我們根本不需要它們——沒有它們我們也能過得很好。如果我們的每個匿名模組類別需要一些不同的行為,其他人沒有的自己的特定方法,我們可以輕鬆添加它們:
MonitoringSystem generalModule = new MonitoringSystem() {

   @Override
   public void startMonitoring() {
       System.out.println("Monitoring of general indicators has started!");
   }

   public void someSpecificMethod() {

       System.out.println("Specific method for first module only");
   }
};
Oracle 文件有一個很好的建議:“如果您需要一次性使用本機類,請使用匿名類。” 匿名類別是一個成熟的內部類別。因此,它可以存取外部類別變量,包括靜態變數和私有變數:
public class Main {

   private static int currentErrorsCount = 23;

   public static void main(String[] args) {

       MonitoringSystem errorModule = new MonitoringSystem() {

           @Override
           public void startMonitoring() {
               System.out.println("Bug Tracking Monitoring Started!");
           }

           public int getCurrentErrorsCount() {

               return currentErrorsCount;
           }
       };
   }
}
它們與本地類別有一些共同點:它們僅在定義它們的方法內部可見。errorModule在上面的範例中,任何在方法之外存取物件的嘗試都main()將失敗。還有一個匿名類別從其「祖先」——內部類別繼承下來的一個更重要的限制:匿名類別不能包含靜態變數和方法。如果我們嘗試將上面範例中的方法設為getCurrentErrorsCount()靜態,編譯器將拋出錯誤:
//error! Inner classes cannot have static declarations
public static int getCurrentErrorsCount() {

   return currentErrorsCount;
}
如果我們嘗試聲明靜態變量,我們會得到相同的結果:
MonitoringSystem errorModule = new MonitoringSystem() {

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

   @Override
   public void startMonitoring() {
       System.out.println("Bug Tracking Monitoring Started!");
   }

};
最後,我可以向您推荐一個關於匿名類主題的精彩視頻,其中對該主題的解釋盡可能簡單明了:)
那麼我們今天的課程就到此結束了!儘管我們已經介紹了最後一組嵌套類,但我們還沒有完成這個主題。接下來我們將學習關於嵌套類別的哪些內容?你一定很快就會知道!:)
留言
TO VIEW ALL COMMENTS OR TO MAKE A COMMENT,
GO TO FULL VERSION