淺談Java的匿名類

在實際的項目中看到一個很奇怪的現(xiàn)象烤送,Java可以直接new一個接口寒随,然后在new里面粗暴的加入實現(xiàn)代碼。就像下面這樣帮坚。那么問題來了妻往,new出來的對象沒有實際的類作為載體,這不是很奇怪嗎试和?

思考以下代碼的輸出是什么讯泣?

Runnable x = new Runnable() {  
    @Override  
    public void run() {  
        System.out.println(this.getClass());  
    }  
};  
x.run();  

實際答案是出現(xiàn)xxxx$1這樣一個類名,它是編譯器給定的名稱阅悍。

匿名類

匿名類相當(dāng)于在定義類的同時再新建這個類的實例好渠。我們來看看匿名類的編譯結(jié)果。

這個類的代碼如下:

public class Test {  
  public void test() {  
    Runnable r = new Runnable(){  
      @Override  
      public void run(){  
        System.out.println("hello");  
      }  
    };  
  }  
}  

來看看它的編譯結(jié)果节视,通過javap反向編譯Test.class拳锚,得到的結(jié)果如下:

SourceFile: "Test.java"  
EnclosingMethod: #20.#21                // Test.test  
InnerClasses:  
     #6; //class Test$1  

發(fā)現(xiàn)了一個字段叫EnclosingMethod,說明這個類是定義在Test.test方法下的寻行。那現(xiàn)在有個問題霍掺,如果有兩個test方法,會出現(xiàn)什么呢拌蜘?

原來是旁邊這個注釋不太準(zhǔn)確杆烁,實際上會包含函數(shù)簽名的。請看Constant Pool部分简卧,這里的#21指向了這個函數(shù)簽名兔魂。

#21 = NameAndType        #34:#16        // test:()V  

匿名類的語法

這里舉一個簡單的例子:

Runnable hello = new Runnable() {  
    public void run() {  
        System.out.println("hello");  
    }  
};  

一個匿名類由以下幾個部分組成:

  1. new操作符
  2. Runnable:接口名稱。這里還可以填寫抽象類举娩、普通類的名稱析校。
  3. ():這個括號表示構(gòu)造函數(shù)的參數(shù)列表。由于Runnable是一個接口晓铆,沒有構(gòu)造函數(shù)勺良,所以這里填一個空的括號表示沒有參數(shù)。
  4. {...}:大括號中間的代碼表示這個類內(nèi)部的一些結(jié)構(gòu)骄噪。在這里可以定義變量名稱尚困、方法。跟普通的類一樣链蕊。

訪問權(quán)限

那么匿名內(nèi)部類能訪問哪些東西呢事甜?按照規(guī)則谬泌,可以訪問如下內(nèi)容:

  1. 訪問外層Class里面的字段。
  2. 不能訪問外層方法中的本地變量逻谦。除非變量是final掌实。
  3. 如果內(nèi)部類的名稱和外面能訪問的名稱相同,則會把名稱覆蓋掉邦马。
public class A {  
    private int foo;  
    public void test() {  
        Runnable r = new Runnable() {  
            System.out.println(foo);  
        };  
    }  
}  

匿名類里面不可以有的東西:
1.不能定義靜態(tài)初始化代碼塊(Static Initializer)贱鼻。比如下面的代碼是不符合語法的:

public class A {  
    public void test() {  
        Runnable r = new Runnable() {  
            static { System.out.println("hello"); }  
        };  
    }  
}  

2.不能在匿名類里面定義接口。

比如:

public class A {  
    public void test() {  
        Runnable r = new Runnable() {  
            public interface Hello { };  
        };  
    }  
}  

和上面一樣滋将,也是為了語義的清晰邻悬。interface只能定義靜態(tài)的。

3.不能在匿名類中定義構(gòu)造函數(shù)随闽。

public class A {  
    public void test() {  
        Runnable r = new Runnable() {  
            public Runnable() { }  
        };  
    }  
} 

因為匿名類沒有名字父丰,而構(gòu)造函數(shù)需要把類名作為方法名才能看成構(gòu)造函數(shù)。
匿名類中可以包含的東西有:

  1. 字段
  2. 方法
  3. 實例初始化代碼
  4. 本地類

為什么不能定義靜態(tài)初始化代碼

事實上掘宪,內(nèi)部類中不能定義任何靜態(tài)的東西蛾扇。

關(guān)鍵字:Inner class cannot have static declarations

參考資料:http://stackoverflow.com/questions/975134/why-cant-we-have-static-method-in-a-non-static-inner-class

StackOverFlow上看起來有一種解釋如下。

首先來看一個內(nèi)部類魏滚。

public class A {  
  public class B {  
  }  
}  

它編譯之后镀首,會變成下面這種含義:

public class A {  
  public static class B {  
    private final A parent;  
    public B(A parent) {  
      this.parent = parent;  
    }  
  }  
} 

所以,按照這么說栏赴,內(nèi)部類就是一種語法糖蘑斧。當(dāng)我們定義靜態(tài)變量時,就會產(chǎn)生下面這種歧義须眷。下面的代碼看起來沒什么問題竖瘾。

public class A {  
  private int a;  
  public class B {  
    public static void test() {  
      a = 1;  
    }  
  }  
}  

但是編譯之后,問題就來了花颗。

public class A {  
  private int a;  
  public static class B {  
    private final A parent;  
    public B (A parent) { this.parent = parent; }  
    public static void test() {  
      parent.a = 1; // 這里有語法錯誤  
    }  
  }  
}  

所以捕传,歸根結(jié)底,Java為了保持清晰的語法扩劝,不允許這種有歧義的語法存在庸论。

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市棒呛,隨后出現(xiàn)的幾起案子聂示,更是在濱河造成了極大的恐慌,老刑警劉巖簇秒,帶你破解...
    沈念sama閱讀 218,204評論 6 506
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件鱼喉,死亡現(xiàn)場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)扛禽,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,091評論 3 395
  • 文/潘曉璐 我一進(jìn)店門锋边,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人编曼,你說我怎么就攤上這事豆巨。” “怎么了掐场?”我有些...
    開封第一講書人閱讀 164,548評論 0 354
  • 文/不壞的土叔 我叫張陵往扔,是天一觀的道長。 經(jīng)常有香客問我刻肄,道長瓤球,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,657評論 1 293
  • 正文 為了忘掉前任敏弃,我火速辦了婚禮,結(jié)果婚禮上噪馏,老公的妹妹穿的比我還像新娘麦到。我一直安慰自己,他們只是感情好欠肾,可當(dāng)我...
    茶點故事閱讀 67,689評論 6 392
  • 文/花漫 我一把揭開白布瓶颠。 她就那樣靜靜地躺著,像睡著了一般刺桃。 火紅的嫁衣襯著肌膚如雪粹淋。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,554評論 1 305
  • 那天瑟慈,我揣著相機(jī)與錄音桃移,去河邊找鬼。 笑死葛碧,一個胖子當(dāng)著我的面吹牛借杰,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播进泼,決...
    沈念sama閱讀 40,302評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼蔗衡,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了乳绕?” 一聲冷哼從身側(cè)響起绞惦,我...
    開封第一講書人閱讀 39,216評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎洋措,沒想到半個月后济蝉,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,661評論 1 314
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 37,851評論 3 336
  • 正文 我和宋清朗相戀三年堆生,在試婚紗的時候發(fā)現(xiàn)自己被綠了专缠。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 39,977評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡淑仆,死狀恐怖涝婉,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情蔗怠,我是刑警寧澤墩弯,帶...
    沈念sama閱讀 35,697評論 5 347
  • 正文 年R本政府宣布,位于F島的核電站寞射,受9級特大地震影響渔工,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜桥温,卻給世界環(huán)境...
    茶點故事閱讀 41,306評論 3 330
  • 文/蒙蒙 一引矩、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧侵浸,春花似錦旺韭、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,898評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至澳腹,卻和暖如春织盼,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背酱塔。 一陣腳步聲響...
    開封第一講書人閱讀 33,019評論 1 270
  • 我被黑心中介騙來泰國打工沥邻, 沒想到剛下飛機(jī)就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人延旧。 一個月前我還...
    沈念sama閱讀 48,138評論 3 370
  • 正文 我出身青樓谋国,卻偏偏與公主長得像,于是被迫代替她去往敵國和親迁沫。 傳聞我的和親對象是個殘疾皇子芦瘾,可洞房花燭夜當(dāng)晚...
    茶點故事閱讀 44,927評論 2 355

推薦閱讀更多精彩內(nèi)容