談談Java的匿名內部類別
在很多時候,我們需要在類別的內部初始化一個靜態的Map或List,然後保存一下常數值提供給類別內部方法使用。
我們通常的做法是:
先初始化一個Map的靜態變數。
接著在靜態區塊加入常數值:
Java程式碼
private final static Map<String, String> CONSTANT = new HashMap<String, String>(); static { CONSTANT.put("1", "one"); CONSTANT.put("2", "two"); }
其實還可以這麼寫:
Java程式碼
private final static Map<String, String> CONSTANT = new HashMap<String, String>() { { put("1", "one"); put("2", "two"); } };
程式碼
new Thread() { public void run() { System.out.println("Thread running!"); }; }.start();
Java程式碼
Thread thread = new Thread() { public void run() { System.out.println("Thread running!"); }; }; thread.start();
建立完匿名類別的實例後,沒有立即執行start(),建立實例和執行實例的方法分開。
兩者的差異相當於:
Java程式碼
//1 new User().setName("Boyce Zhang"); //2 User user = new User(); user.setName("Boyce Zhang");
Java程式碼
new Thread() { public void run() { System.out.println("Thread running!"); }; { start(); } };
局部程式碼區塊內的語句是在建立該類別的實例後由類別載入器隱含立即執行的。
相當於:
Java程式碼
public class MyThread extends Thread { { start(); } public void run() { System.out.println("Thread running!"); }; }
Java程式碼
private final static Map<String, String> CONSTANT = new HashMap<String, String>() { { put("1", "one"); put("2", "two"); } };
宣告並實例化一個HashMap的子類別(子類別沒有重寫父類別HashMap的任何方法),並且在子類別的類別局部程式碼區塊呼叫父類別HashMap的put()方法。
最後宣告一個Map介面引用CONSTANT指向實例化的HashMap子類別的實例。根據前面的例子我們知道,類別局部程式碼區塊中的put()方法呼叫將在HashMap的匿名子類別被實例化後由類別載入器隱含的執行。
其實,對於Java的任何類別或接口,都可以聲明一個匿名類別繼承或實現它。如:
Java程式碼
//重写父类方法,局部代码块调用自己重写过的父类方法。 List<String> list = new ArrayList<String>() { public boolean add(String e) { System.out.println("Cannot add anything!"); } //代码块的顺序在前后都无所谓,可以出现在类范围的任何位置。 { add("Boyce Zhang"); } }; //局部代码块调用父类方法。 dao.add(new User(){ { setName("Boyce Zhang"); setAge(26); } }); //重写父类方法 ThreadLocal<User> threadLocal = new ThreadLocal<User>() { protected String initialValue() { return new User("Boyce Zhang", 26); } };
而且也可以在其類別的局部程式碼區塊中執行自己的方法或其父類別的方法。
這並不是匿名內部類別的特殊語法,而是Java的語法,對於任何類別都適用。
這種寫法常常就是用在實例化一個類別後立即執行某些方法做一些類別實例的資料初始化什麼的。
其作用和先實例化一個類,在使用其引用調用需要立即調用的方法是一樣的,如:
Java代碼
Map<String, String> map = new HashMap<String, String>(); map.put("1", "one"); map.put("2", "two");
效果有一點兒像Javascript裡的即時函數。但是有本質的區別。
因為Javascript沒有類別的概念,或是說Javascript中function就是類別,類別就是function,所以即時函數是載入完後執行整個function。而Java的局部程式碼區塊是可以選擇執行類別的任何方法。
當然這種寫法也有其缺點:
每一個內部類別的實例都會隱性的持有一個指向外部類別的引用(靜態內部類別除外),這樣一方面是多餘的引用浪費,另一方面當串行化這個子類別實例時外部類別也會被不知不覺的串列化,如果外部類別沒有實作serialize介面時,就會報錯。
更多談談Java的匿名內部類相關文章請關注PHP中文網!

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

匿名內部類別可導致記憶體洩漏,問題在於它們持有外部類別的引用,從而阻止外部類別被垃圾回收。解決方法包括:1.使用弱引用,當外部類別不再被強引用持有時,垃圾回收器會立即回收弱引用物件;2.使用軟引用,垃圾回收器會在進行垃圾回收時需要記憶體時才回收軟引用物件。在實戰中,例如Android應用程式中,可以透過使用弱引用來解決因匿名內部類別引起的記憶體洩漏問題,從而在不需要監聽器時回收匿名內部類別。

匿名內部類別是Java中沒有明確名稱、透過new表達式創建的特殊內部類,主要用於實作特定介面或擴展抽象類,並在創建後立即使用。常見的匿名內部類別設計模式包括:適配器模式:將一個介面轉換為另一個介面。策略模式:定義和替換演算法。觀察者模式:註冊觀察者並處理事件。它在實際應用中非常有用,例如按字串長度排序TreeSet、建立匿名執行緒等。

匿名內部類別在Java中作為方便建立子類別、簡化程式碼和處理事件(例如按鈕點擊)的特殊內部類別。實戰案例包括:事件處理:使用匿名內部類別為按鈕新增點選事件監聽器。資料轉換:使用Collections.sort方法和匿名內部類別作為比較器對集合進行排序。

匿名內部類別的效能問題在於每次使用都會重新創建,可透過以下策略最佳化:1.將匿名內部類別儲存在局部變數中;2.使用非靜態內部類別;3.使用lambda表達式。實戰測試顯示lambda表達式最佳化效果最佳。

匿名內部類別的限制包括:無法存取外部局部變數;無法直接存取外部this引用;無法拋出checked異常;程式碼冗餘;無法序列化。

匿名內部類別可簡化多執行緒程式碼的創建,無需命名,支援即時定義和使用執行緒類別。主要優勢在於簡化程式碼,而限制是無法擴展。在需要快速建立一兩個執行緒時使用,保持程式碼簡短,如果需要更複雜的邏輯,應建立單獨的類別檔案。
