匿名內部類適合創建那種只需要一次使用的類,例如命令模式時所需要的Command對象。匿名內部類的語法有點奇怪,創建匿名內部類時會立即創建一個該類的實例,這個類定義立即消失,匿名內部類不能重複使用。
定義匿名內部類的格式如下:
- new 父類構造器(參數列表)|實現接口()
- {
- //匿名內部類的類體部分
- }
從上面定義可以看出,匿名內部類必須繼承一個父類,或實現一個接口,但最多隻能繼承一個父類,或實現一個接口。
關於匿名內部類還有如下兩條規則:
1)匿名內部類不能是抽象類,因爲系統在創建匿名內部類的時候,會立即創建內部類的對象。因此不允許將匿名內部類定義成抽象類。
2)匿名內部類不能定義構造器,因爲匿名內部類沒有類名,所以無法定義構造器,但匿名內部類可以定義實例初始化塊,通過實例初始化塊來完成構造器需要完成的事情。
最常用的創建匿名內部類的方式是需要創建某個接口類型的對象,如下程序所示:
- interface Product{
- public double getPrice();
- public String getName();
- }
- public class TestAnonymous{
- public void test(Product p){
- System.out.println("購買了一個"+p.getName()+",花掉 了"+p.getPrice());
- }
- public static void main(String[]args){
- TestAnonymous ta = new TestAnonymous();
- ta.test(new Product(){
- public double getPrice(){
- return 567;
- }
- public String getName(){
- return "AGP顯卡";
- }
- });
- }
- }
上面程序中的TestAnonymous類定義了一個test方法,該方法需要一個Product對象作爲參數,但Product只是一個接口,無法直接創建對象,因此此處考慮創建一個Product接口實現類的對象傳入該方法---如果這個Product接口實現類需要重複使用,則應該經該實現類定義一個獨立類;如果這個Product接口實現類只需一次使用,則可採用上面程序中的方式,定義一個匿名內部類。
正如上面程序中看到,定義匿名類不需要class關鍵字,而是在定義匿名內部類時直接生成該匿名內部類的對象。上面粗體字代碼部分就是匿名類的類體部分。由於匿名內部類不能是抽象類,所以匿名內部類必須實現它的抽象父類或者接口裏包含的所有抽象方法。
對於上面創建Product實現類對象的代碼,可以拆分成如下代碼:
- class AnonymousProduct implements Product{
- public double getPrice(){
- return 567;
- }
- public String getName(){
- return "AGP顯卡";
- }
- }
- ta.test(new AnonymousProduct());
當通過實現接口來創建匿名內部類時,匿名內部類也不能顯示創建構造器,因此匿名內部類只有一個隱式的無參數構造器,故new接口名後的括號裏不能傳入參數值。但如果通過繼承父類來創建匿名內部類是,匿名內部類將擁有和父類相似的構造器,此處的相似指的是擁有相同的形參列表。
- abstract class Device{
- private String name;
- public Device(){
- }
- public Device(String name){
- this.name = name;
- }
- public abstract double getPrice();
- //此處省略了name屬性的setter和getter方法
- }
- public class AnonymousInner{
- public void test(Device d){
- System.out.println("購買了一個"+d.getName()+",花掉了"+d.getPrice());
- }
- public static void main(String[] args){
- AnonymousInner ai = new AnonymousInner();
- //調用有參數的構造器創建Device匿名實現類的對象
- ai.test(new Device("電子示波器"){
- public double getPrice(){
- return 67;
- }
- });
- //調用無參數的構造器創建Device匿名實現類的對象
- Device d = new Device(){
- //初始化塊
- {
- System.out.println("匿名內部類的初始化塊...");
- }
- //實現抽象方法
- public double getPrice(){
- return 56;
- }
- public Sting getName(){
- return "鍵盤";
- }
- };
- ai.test(d);
- }
- }
上面程序創建了一個抽象父類Device,這個抽象父類裏包含兩個構造器:一個無參數的,一個有參數的。當創建以Device父類的匿名內部類時,即可以傳入參數(如上面程序中第一段粗體字部分),也可以不傳入參數(如上面程序中第二段粗體字部分)。
當創建匿名內部類時,必須實現接口或抽象父類裏的所有抽象方法。如果有需要,也可以重寫父類中的普通方法,如上面程序的第二段粗體字代碼部分,匿名內部類重寫了抽象父類Device類的getName方法,其中getName方法並不是抽象方法。
如果匿名內部類需要訪問外部類的局部變量,則必須使用final修飾符來修飾外部類的局部變量,
否則系統將報錯。
- interface A{
- void test();
- }
- public class TestA{
- public static void main(Strign[] args){
- int age = 0;
- A a = new A(){
- public void test(){
- //下面語句將提示錯誤:匿名內部類內訪問局部變量必須使用final修飾
- System.out.println(age);
- }
- };
- }
- }
上面程序中粗體子代碼是匿名內部類訪問了外部類的局部變量,由於age變量沒有使用final修飾符修飾,所以粗體字代碼將引起編譯異常。