---------------------- <a href="http://edu.csdn.net" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="blank">ASP.Net+Android+IO開發S</a>、<a href="http://edu.csdn.net" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="blank">.Net教育訓練</a>、期待與您交流! ----------------------
我在上一篇部落格中說到匿名内部類,裡面提到一句話,說匿名内部類是沒有構造函數的,但是卻可以執行個體化一個對象,這是百度的,我第一次看到這句話時楞了一下,為什麼呢?沒有構造函數,拿什麼區建立執行個體呢?
查了查,原來是因為匿名内部類連名字的都沒有,怎麼會有構造函數呢,總不能寫一對括号吧,後來想想内部類其實類似父子類,既然繼承父類,肯定得調用父類的構造函數啦,于是我就在網上查了一篇部落格,位址是http://zangxt.iteye.com/blog/421560,裡面就舉例說明了匿名内部類調用父類的構造函數,内容我就直接拿過來了:
Java代碼
- package testtest;
- public class Main {
- public static void main(String[] args) {
- InnerTest inner = new InnerTest();
- Test t = inner.get(3);
- System.out.println(t.getI());
- }
- }
- class Test {
- private int i;
- public Test(int i) {
- this.i = i;
- }
- public int getI() {
- return i;
- }
- }
- class InnerTest {
- public Test get(int x) {
- return new Test(x) {
- @Override
- public int getI() {
- return super.getI() * 10;
- }
- };
- }
- }
編譯之後得到4個class檔案:Test.class,InnerTest.class,InnerTest$1.class以及Main.class。容易看出來,Main.class是測試類的class檔案,Test.class是超類Test的class檔案,InnerTest.class是InnerTest 的class檔案,最值得關注的就是匿名内部類的class檔案InnerTest$1.class。
首先javap -c InnerTest$1
Java代碼
- Compiled from "Main.java"
- class testtest.InnerTest$1 extends testtest.Test{
- final testtest.InnerTest this$0;
- testtest.InnerTest$1(testtest.InnerTest, int);
- Code:
- 0: aload_0
- 1: aload_1
- 2: putfield #1; //Field this$0:Ltesttest/InnerTest;
- 5: aload_0
- 6: iload_2
- 7: invokespecial #2; //Method testtest/Test."<init>〈init〉":(I)V
- 10: return
- public int getI();
- Code:
- 0: aload_0
- 1: invokespecial #3; //Method testtest/Test.getI:()I
- 4: bipush 10
- 6: imul
- 7: ireturn
- }
- </init>
很明顯,雖然我們看來是匿名内部類,但編譯的時候給這個類指定了名字InnerTest$1,而且看出來是繼承自Test:
- class testtest.InnerTest$1 extends testtest.Test
而且在這個類有構造方法:
- testtest.InnerTest$1(testtest.InnerTest, int);
這裡也很容易了解,兩個參數,一個是匿名内部類的外部類引用直接傳了進來,這也是我們能在内部類中直接通路外部類成員的實作原理。另外一個就是int類型的參數了。也就是說其實編譯器自動的給我們添加了帶參數的構造方法。繼續往下看:
7: invokespecial #2; //Method testtest/Test."<init>":(I)V
這就是調用父類的構造方法了 。
接下來 ,我們 隻要看 InnerTest中 get方法 的 實作就可以了 :
Csharp代碼
- Compiled from "Main.java"
- class testtest.InnerTest extends java.lang.Object{
- testtest.InnerTest();
- Code:
- 0: aload_0
- 1: invokespecial #1; //Method java/lang/Object."<init>〈init〉":()V
- 4: return
- public testtest.Test get(int);
- Code:
- 0: new #2; //class testtest/InnerTest$1
- 3: dup
- 4: aload_0
- 5: iload_1
- 6: invokespecial #3; //Method testtest/InnerTest$1."<init>〈init〉":(Ltesttest/InnerTest;I)V
- 9: areturn
- }
- </init></init><pre></pre>
到這裡一切都清楚了,InnerTest中對待匿名内部類和對待普通類一樣,先是
- 0: new #2; //class testtest/InnerTest$1
然後調用其構造方法:
- 6: invokespecial #3; //Method testtest/InnerTest$1."〈init〉":(Ltesttest/InnerTest;I)V<pre></pre>
但如果匿名内部類是實作的一個接口呢?接口也是沒有構造函數的,為什麼呢?因為接口沒有具體的實作啊,
如果有構造函數就不算接口了,而是一個抽象函數,so,這下子父類也沒有構造函數了,匿名内部類調用誰去?
大神就是多,她告訴我繼承和實作是不一樣的,如果普通類沒指定父類隻實作了接口,那這個類就預設是Object的子類。
好吧,再舉個實作接口的例子:
- public class Main {
- public static void main(String[] args) {
- InnerTest inner = new InnerTest();
- Test t = inner.get();
- System.out.println(t.getI());
- }
- }
- interface Test {
- public int getI();
- }
- class InnerTest {
- public Test get() {
- return new Test() {
- // @Override
- public int getI() {
- return 10;
- }
- };
- }
- }
- javap -c InnerTest$$$$$$$$1
複制代碼 運作javap -c InnerTest$1的結果
- class InnerTest$$$$1 implements Test {
- final InnerTest this$$$$0;
- InnerTest$$$$1(InnerTest);
- Code:
- 0: aload_0
- 1: aload_1
- 2: putfield #1 // Field this$$$$0:LInnerTest;
- 5: aload_0
- 6: invokespecial #2 // Method java/lang/Object."<init>":
- ()V
- 9: return
- public int getI();
- Code:
- 0: bipush 10
- 2: ireturn
- }
複制代碼 6: invokespecial #2 // Method java/lang/Object."<init>" 可以看到确實是調用的Object的構造函數。
是以,就算匿名内部類沒有名字,編譯器還是會自動為其加上一個名字,然後用它的父類構造函數去将其初始化。
---------------------- <a href="http://edu.csdn.net" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="blank">ASP.Net+Android+IO開發S</a>、<a href="http://edu.csdn.net" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="_blank" rel="external nofollow" target="blank">.Net教育訓練</a>、期待與您交流! ----------------------