List l1 = new ArrayList(); // 普通對象
List l2 = new ArrayList() {}; // 匿名內部類(無初始化塊)
List l3 = new ArrayList() {{ }}; // 匿名內部類(含初始化塊)
運行結果:l1.getClass() == l2.getClass() 為 false,說明三者類型完全不同。
匿名內部類無法定義構造函數(因為沒有類名),Java 編譯器允許使用 實例初始化塊 替代:
// 寫法等價於
class Sub extends ArrayList {
{ // 實例初始化塊 - 相當於構造函數體
System.out.println("初始化邏輯");
}
Sub(int capacity) {
super(capacity); // 必須顯式調用父類構造函數
}
}
List l3 = new Sub(10);
// 匿名內部類帶參數
List l5 = new ArrayList(5) {
{
System.out.println("初始化塊執行");
}
};
// 編譯器生成的等價代碼
class Sub extends ArrayList {
{
System.out.println("初始化塊執行");
}
Sub(int num) {
super(num); // 先調用父類對應構造函數
}
}
關鍵點:匿名內部類初始化時,先調用父類同參構造函數,再執行自身初始化塊。
// 多個初始化塊合法
List l4 = new ArrayList() {{}{}{}};
// 突破私有封裝 - 實戰:屬性拷貝
Field[] fields = fromClass.getDeclaredFields();
for (Field field : fields) {
field.setAccessible(true); // 關鍵:暴力反射訪問私有屬性
field.set(dest, field.get(src));
}
編譯後生成 OuterClass$1.class、OuterClass$2.class 等文件,編號對應聲明順序。每個匿名類都是獨立的 .class 文件,繼承自目標類或實現目標接口。
button.addActionListener(e -> { ... }) (Java 8+ Lambda 替代)new Thread(() -> { ... }).start()Collections.sort(list, new Comparator() { ... })new HashMap() {{ put("k", "v"); }} (僅適合測試/原型,生產慎用)serialVersionUID 不穩定,跨 JVM 反序列化易失敗匿名內部類通過初始化塊模擬構造函數,編譯器自動處理父類構造函數鏈調用。理解其本質是「編譯器語法糖 + 運行期動態生成子類」,有助於正確使用並避開常見陷阱。現代 Java 建議優先使用 Lambda 表達式替代單方法介面的匿名類寫法。