JAVA匿名內部類

簡單地說:匿名內部類就是沒有名字的內部類。什麼情況下需要使用匿名內部類?如果滿足下面的一些條件,使用匿名內部類是比較合適的:
  ·只用到類的一個實例。 
  ·類在定義後馬上用到。 
  ·類非常小(SUN推薦是在4行代碼以下) 
  ·給類命名並不會導致你的代碼更容易被理解。
  在使用匿名內部類時,要記住以下幾個原則:
  ·匿名內部類不能有構造方法。 
  ·匿名內部類不能定義任何靜態成員、方法和類。 
  ·匿名內部類不能是public,protected,private,static。 
  ·只能創建匿名內部類的一個實例。
·一個匿名內部類一定是在new的後面,用其隱含實現一個接口或實現一個類。 
  ·因匿名內部類爲局部內部類,所以局部內部類的所有限制都對其生效。  
下面的例子看起來有點奇怪:
//在方法中返回一個匿名內部類
public class Parcel6 {
        public Contents cont() {
                return new Contents() {
                     private int i = 11;
 
                     public int value() {
                            return i;
                     }
              }; // 在這裏需要一個分號
        }
 
        public static void main(String[] args) {
                Parcel6 p = new Parcel6();
                Contents c = p.cont();
        }
}
cont()方法將下面兩個動作合併在一起:返回值的生成,與表示這個返回值的類的定義!進一步說,這個類是匿名的,它沒有名字。更糟的是,看起來是你正要創建一個Contents對象:
return new Contents()
但是,在到達語句結束的分號之前,你卻說:“等一等,我想在這裏插入一個類的定義”:
return new Contents() { 
        private int i = 11; 
        public int value() { return i; } [Page]
};
這種奇怪的語法指的是:“創建一個繼承自Contents的匿名類的對象。”通過new 表達式返回的引用被自動向上轉型爲對Contents的引用。匿名內部類的語法是下面例子的簡略形式:
class MyContents implements Contents { 
        private int i = 11; 
        public int value() { return i; } 
}
return new MyContents();
在這個匿名內部類中,使用了缺省的構造器來生成Contents。下面的代碼展示的是,如果你的基類需要一個有參數的構造器,應該怎麼辦:
public class Parcel7 {
    public Wrapping wrap(int x) {
        return new Wrapping(x) {
            public int value() {
                return super.value() * 47;
            }
        }; 
    }
    public static void main(String[] args) {
        Parcel7 p = new Parcel7();
        Wrapping w = p.wrap(10);
    }
}
只需簡單地傳遞合適的參數給基類的構造器即可,這裏是將x 傳進new Wrapping(x)。在匿名內部類末尾的分號,並不是用來標記此內部類結束(C++中是那樣)。實際上,它標記的是表達式的結束,只不過這個表達式正巧包含了內部類罷了。因此,這與別的地方使用的分號是一致的。
 
如果在匿名類中定義成員變量,你同樣能夠對其執行初始化操作:
public class Parcel8 {
    // Argument must be final to use inside
    // anonymous inner class:
    public Destination dest(final String dest) {
        return new Destination() {
            private String label = dest;
            public String readLabel() { return label; }
        };
    }
    public static void main(String[] args) {
        Parcel8 p = new Parcel8();
        Destination d = p.dest(/"Tanzania/");
    }

如果你有一個匿名內部類,它要使用一個在它的外部定義的對象,編譯器會要求其參數引用是final 型的,就像dest()中的參數。如果你忘記了,會得到一個編譯期錯誤信息。如果只是簡單地給一個成員變量賦值,那麼此例中的方法就可以了。但是,如果你想做一些類似構造器的行爲,該怎麼辦呢?在匿名類中不可能有已命名的構造器(因爲它根本沒名字!),但通過實例初始化,你就能夠達到爲匿名內部類“製作”一個構造器的效果。像這樣做:

abstract class Base {
    public Base(int i) {
        System.out.println(/"Base constructor, i = /" + i);
    }
    public abstract void f();
}
public class AnonymousConstructor {
    public static Base getBase(int i) {
        return new Base(i) {
            {
                System.out.println(/"Inside instance initializer/");
            }
            public void f() {
                System.out.println(/"In anonymous f()/");
            }
        };
    }
    public static void main(String[] args) {
        Base base = getBase(47);
        base.f();
    }
}

在此例中,不要求變量i 一定是final 的。因爲i 被傳遞給匿名類的基類的構造器,它並不會在匿名類內部被直接使用。下例是帶實例初始化的“parcel”形式。注意dest()的參數必須是final,因爲它們是在匿名類內被使用的。
public class Parcel9 {
    public Destinationdest(final String dest, final float price) {
        return new Destination() {
            private int cost;
            // Instance initialization for each object:
            {
                cost = Math.round(price);
                if(cost > 100)
                System.out.println(/"Over budget!/");
            }              
            private String label = dest;
            public String readLabel() { return label; }
        };
    }
    public static void main(String[] args) {
        Parcel9 p = new Parcel9();
        Destination d = p.dest(/"Tanzania/", 101.395F);
    }
}
在實例初始化的部分,你可以看到有一段代碼,那原本是不能作爲成員變量初始化的一部分而執行的(就是if 語句)。所以對於匿名類而言,實例初始化的實際效果就是構造器。當然它受到了限制:你不能重載實例初始化,所以你只能有一個構造器。

發佈了24 篇原創文章 · 獲贊 3 · 訪問量 21萬+
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章