1. 程式人生 > >Java中的匿名內部類及其使用技巧

Java中的匿名內部類及其使用技巧

轉載地址: https://blog.csdn.net/tick_tock97/article/details/76944566

前言

在介紹匿名內部類之前,首先我們應該先來了解一下內部類及區域性內部類: 內部類

內部類(inner class)是定義在另一個類中的類,內部類中的方法可以訪問建立該內部類的類(我們稱其為外圍類 outer class)的域中所有資料(包括私有/private資料)。並且,內部類可以對同一個包中的其他類隱藏起來。

但是由於內部類是一種編譯器現象,在虛擬機器中只存在常規類檔案,所以在編譯過程中,內部類被翻譯成”外圍類名$內部類名”的一個常規類,另一方面由於內部類有非常高的特權(可以訪問外圍類中的私有域)所以在一些特殊手段下(比如利用十六進位制編輯器建立一個虛擬機器指令呼叫該內部類),有可能會導致外圍類內的私有域資料洩露。

區域性內部類

當某一個類只被唯一一個方法呼叫時,就可以採用區域性內部類來定義它(該類定義在某方法內部)。區域性類不能使用public或者private訪問說明符進行宣告,它的作用域被限定在宣告這個區域性類的方法(或程式碼塊)中。並且,區域性類對外部世界是完全隱藏起來的,及時定義它的方法所在的外圍類也不可以訪問它。

由於區域性內部類對於外圍類不可見,所以不存在通過其他手段呼叫該區域性內部類的危險,也就極大的保證了安全性。

正文

匿名內部類定義

假如一個區域性內部類只被用一次(只用它構建一個物件),就可以不用對其命名了,這種沒有名字的類被稱為匿名內部類(anonymous inner class),其程式碼格式通常為:

new SuperType(construction parameters){
    inner class methods and data
};
  • 1
  • 2
  • 3

其中SuperType可以是一個介面(匿名內部類將要實現的介面),也可以是一個類(匿名內部類將要擴充套件它)。匿名內部類的可見域與區域性內部類相同。

匿名內部類的構造器

由於構造器的名字必須與類名相同,而匿名內部類沒有類名,所以匿名類不能含有構造器。取而代之的是將構造器引數傳遞給超類(superclass)的構造器。

當匿名類實現某個介面的時候,一定不能存在任何構造引數。這時,程式碼格式構成變成如下所示:

new InterfaceType(){
    methods and data
};
  • 1
  • 2
  • 3

匿名內部類的注意事項

建立一個與超類類似,但不完全相同的匿名子類非常容易,但這樣的子類物件在使用equals方法時要特別當心,我們在定義equals時,一般要對型別進行測試:

if(getClass() != other.getClass()) return false;
  • 1

這個測試條件在用於匿名子類時會失效!

匿名內部類的使用技巧

這裡著重介紹一下雙括號初始化(double brace initialization)技巧

假設我們想構造一個數組列表,並將它傳給某個方法:

ArrayList<String> friends = new ArrayList<>();
friends.add("Harry");
friends.add("Tony");
invite(friends);
  • 1
  • 2
  • 3
  • 4

若這個friends陣列之後不會再使用的話,我們可以把它構造成一個匿名列表:

invite(new ArrayList<String>(){{add("Harry");add("Tony");}});
  • 1

這裡的兩層括號,外層括號建立了一個 ArrayList的匿名子類。內層括號定義了一個該匿名子類的構造塊(構造物件時會自動執行的程式碼塊)。

由於匿名內部類的訪問特性與區域性內部類相同,所以僅僅做了這一個小小的改動不僅保護了資料(如果不是這樣做的話,可以用一些特殊方法,得到宣告的friends列表)還精簡了程式碼,何樂而不為呢。