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

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!");
}
}
似乎一切都井井有條。我們有一個由幾個模塊組成的非常連貫的系統。他們每個人都有自己的行為。如果我們需要新模塊,我們可以添加它們,因為我們有一個很容易實現的接口。但是讓我們考慮一下我們的監控系統將如何工作。 
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 機器內部發生以下情況:
- 創建一個未命名的 Java 類來實現該
MonitoringSystem
接口。 - 當編譯器看到這樣的類時,它要求你實現接口的所有方法
MonitoringSystem
(我們做了 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
對象,以三種不同的方式覆蓋了一個方法,並調用了它三次。所有三個模塊都已成功調用並正在運行。同時,我們程序的結構也變得簡單多了!畢竟,現在可以從程序中完全刪除GeneralIndicatorMonitoringModule
、ErrorMonitoringModule
和類!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!");
}
};
而我們今天的課程也結束了!但是即使我們調查了最後一組嵌套類,我們還沒有完成這個話題。關於嵌套類,我們還會學到什麼?你一定會很快發現!:)
GO TO FULL VERSION