匿名內部類的構造器
來看一個例子:
class A{ public B f() { return new B() { { setName("annoyInner"); //非靜態初始塊,等同於構造方法 } //。。。 //可以自定義成員變量、成員方法 //可以重寫父類方法 }; } public static void main(String[] args) { A a = new A(); System.out.println(a.f().getName()); } } class B{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public B() { System.out.println("B的無參構造"); } }
打印結果:
B的無參構造
annoyInner
在匿名類中,可用花括號括起來進行一些必要的初始化操作,表示非靜態初始化塊,等同於構造方法。由於沒有方法名,此構造方法不區分有參無參,那么怎么在匿名構造方法中使用參數呢?
class A{ public B f() { String name = "annoyInner"; return new B() { { setName(name); //直接使用局部變量即可 } //。。。 //可以自定義成員變量、成員方法 //可以重寫父類方法 }; } public static void main(String[] args) { A a = new A(); System.out.println(a.f().getName()); } } class B{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public B() { System.out.println("B的無參構造"); } }
打印結果同上。匿名類中直接使用局部變量或成員變量即可,相當於匿名類的有參構造器(Java 中局部內部類和匿名內部類訪問的局部變量必須由 final 修飾,以保證內部類和外部類的數據一致性。但從 Java 8 開始,添加了 Effectively final 功能,我們可以不加 final 修飾符,由系統默認添加。詳情可點擊《Java8新特性之Effectively final》進行學習。)
接下來又有個問題,匿名類的構造器能不能重載呢?
答案是不能,還是因為匿名類沒有名字,連賦予參數的地方都沒有,但是你可以這樣寫:
class A{ public B f() { return new B() { { setName("annoyInner1"); } { setName("annoyInner2"); } { setName("annoyInner3"); } //... }; } public static void main(String[] args) { A a = new A(); System.out.println(a.f().getName()); } }
打印結果是annoyInner3,這相當於是多個初始化塊,會依次執行,並不是構造器的重載,但是這樣寫跟寫在一個初始化塊中沒有什么區別。
我們都知道匿名類實例化時會默認調用父類的無參構造,如何調用父類的有參構造?加上super(name)是不行的:
class A{ public B f() { return new B("annoyInner") { { //super(name); //編譯報錯 } }; } public static void main(String[] args) { A a = new A(); System.out.println(a.f().getName()); } } class B{ private String name; public String getName() { return name; } public void setName(String name) { this.name = name; } public B() { System.out.println("B的無參構造"); } public B(String name) { this.name = name; System.out.println("B的有參構造"); } }
打印結果如下,直接在匿名類的表達式中使用父類的有參構造即可
B的有參構造
annoyInner
下面是一個很常見的匿名類的運用,經常看見有人這么寫:
ArrayList<String> list = new ArrayList<String>() {{ add("A"); add("B"); add("C"); }}; Map m = new HashMap() { { put("name","zhangsan"); put("age",18); } };
看到這個,我只想說:
花里胡哨!!!
拿arrayList為例,外層的花括號創建了一個繼承於ArrayList的匿名類,里層的花括號表示在這個匿名類的初始化塊中調用了繼承而來的add方法,實際上這個匿名類和ArrayList沒有什么區別。這樣寫好像是簡潔了一些,但是可讀性也要差一些,也並不會帶來多少性能上的優化,目前本人還不知道會不會引發什么問題。不過取決於個人喜好,用用也無妨。