2011-04-16 54 views
8

我怎樣才能讓這樣的工作:如何使外部類從內部類繼承?

class Outer { 
    int some_member; 

    abstract class InnerBase { 
    abstract void method(); 
    } 
} 

class OuterExtendsInner extends Outer.InnerBase { 
    OuterExtendsInner(Outer o) { o.super(); } 
    void method() { 
    // How do I use some_member here? 
    // Writing Outer.this.some_member -> error about Outer not being an enclosing class 
    // Writing just some_member -> no-go, either 
    } 
} 

的解決方法是在InnerBase方法返回Outer.this和派生類調用,但有另一種方式?

我主要想從外部擴展InnerBase以獲得更好的代碼組織,但是我可以將所有派生類移動到Outer。

+3

「更好的代碼組織」很少涉及內部類,我無法想象它涉及到這樣的事情。 – Anon 2011-04-16 11:57:30

+0

這就是爲什麼我想擴展外部類之外的內部類。我正在實現一個解釋器,並且每個「內部」類對一個類型(名稱,整數等)進行建模。該類型的行爲可能需要或可能不需要對創建它的解釋器對象的引用。我通過將解釋器引用傳遞給每個可能需要它的方法來解決這個問題。 – zvrba 2011-04-16 16:19:59

回答

3

這裏的問題是鏈接InnerBaseOuter的合成字段是私有字段。因此,我們只能從InnerBase內部訪問外部對象,或者如果某些方法或字段提供對同一對象的引用。

+1

+1:謝謝你幫助澄清這個怪事! – 2011-04-16 12:39:09

3

你可以在OuterExtendsInner做到這一點:

class OuterExtendsInner extends Outer.InnerBase { 
    Outer o; 

    OuterExtendsInner(Outer o) { 
     o.super(); 
     this.o = o; 
    } 

    void method() { 
     // now you can reference o.some_member 
     int x = o.some_member; 
    } 
} 
+0

這就是我在問題中已經提出的建議(儘管從InnerBase中的方法返回Outer.this的引用)。 – zvrba 2011-04-16 10:07:58

+0

糟糕,我已經用另一種方式更新了答案。 – WhiteFang34 2011-04-16 10:12:30

+0

此外,OuterExtendsInner中會有兩個Outer.InnerBase實例。一個繼承的和在構造函數中接收到的。你不會談論相同的'some_member'。 – JVerstry 2011-04-16 10:30:05

0

嗯,你的問題是,InnerBase每個實例(我知道這是抽象的)都必須有一個Outer對象的引用。這是嵌套類的語義的一部分。實例化OuterExtendsInner需要這樣的參考。 您可以避免使InnerBase嵌套的類成爲static

+0

這不是問題,問題是如何獲得對這個'Outer'對象的引用。 – 2011-04-16 11:43:43

1

答案是:你不能,因爲它會破壞封裝。只有InnerBase可以訪問Outer的屬性,而不是OuterExtendsInner。這不是直接繼承。 InnerBase不會繼承Outer。

+0

嗯,你可以,因爲Outer的屬性並不是InnerBase的真正屬性,所以它們只是在語法上看起來好像它們一樣(至少,它曾經是 - 我無法想象這會改變)。此外,這個問題並不一定涉及任何直接訪問Outer的私有屬性。 – 2011-04-16 10:31:29

+0

但OuterExtendsInner繼承自InnerBase,因此它應該有權訪問InnerBase有權訪問的所有內容。 – zvrba 2011-04-16 10:36:01

+0

@Robin Green請提供一個操作示例,但您會發現這是不可能的。 OuterExtendsInner不能訪問Outer的屬性。 – JVerstry 2011-04-16 10:39:23

1

我還沒有試過WhiteFang34的回答。它可能工作,但我不清楚它...

如果你真的想在內部類的外部定義一個擴展,而不是在外部類中,最自然的事情就是將它定義爲擴展在另一個外層擴展你的外層類如下:

class Outer { 
    int some_member; 

    abstract class InnerBase { 
    abstract void method(); 
    } 
} 

class OuterExtendsOuter extends Outer { 
    class InnerExtendsInner extends Outer.InnerBase { 
    void method() { 
     System.out.println(some_member); 
    } 
    } 
} 

我還沒有真正運行這個代碼,但它應該工作。

更新:

基於評論線程,我現在已經編譯和運行這兩個我上面的代碼和WhiteFang34的代碼。

兩者實際上都有效,但正如PaŭloEbermann的評論所指出的,兩者都在實例化的內部類中創建了兩個外部副本。

我打算贊成Paŭlo的回答,並且會主張不試圖用這兩種策略來做到這一點,因爲這實際上是對內部類機制的濫用。

只需讓您的擴展內部類生活在相同的外部類!

更新2:

在我的代碼會發生什麼情況的基礎上,使用調試器運行時檢查,並在檢查來自班的javap檢查的輸出,是既InnerBaseOuterExtendsOuter$InnerExtendsInner有一個名爲合成私人最終場this$0。因爲沒有構造被明確地定義,則默認構造被使用,並且該代碼段

OuterExtendsOuter outer = new OuterExtendsOuter(); 
    Outer.InnerBase inner = outer.new InnerExtendsInner(); 

導致這兩個字段到兩個參考outer

換句話說,Paŭlo的評論完全正確。

通過進一步的實驗,如果你在另一個內部類的Outer延長InnerBase同一實際發生的,所以它有什麼與它正在同外部類或它的一個擴展模塊定義,但實際上是一個結果一般如何處理非靜態的內部類。

我懷疑這是記錄在某處,但我沒有看到。

可能最好儘可能少混合繼承和內部類!

+0

這個'InnerExtendsInner'對象有兩個包含類的鏈接(一個用於'InnerExtendsInner'和一個用於'InnerBase'),這偶然地(例如通過默認構造函數)指向相同的對象。 – 2011-04-16 11:50:09

+0

@PaŭloEbermann:我不追隨你。也許我將不得不嘗試實際編譯和運行代碼... – 2011-04-16 11:55:52

+0

我認爲它會工作,但它實際上類似於WhiteFang帶有明確的'Outer'引用的答案。 (我應該做一個形象,但我沒有足夠的空間在這個評論。) – 2011-04-16 12:15:51

1

在InnerBase中只有一個getter方法?

class Outer { 
    int some_member; 

    abstract class InnerBase { 
    abstract void method(); 
    protected int getSome_Member() // This is possible, because Abstract classes can have non-abstract methods. 
    { 
     return some_member; 
    } 
    } 
} 

class OuterExtendsInner extends Outer.InnerBase { 
    OuterExtendsInner(Outer o) { o.super(); } 
    void method() { 
     // you can access "some_member" now 
     int myNumber = getSome_Member(); 

    } 
} 
0

如果將內部類編譯爲「.class」,則外部類可以擴展內部類。現在

,每次編譯它遇到的外部類「擴展內部類」,這是

尚未編譯,編譯器將拋出一個NoClassDefException或ClassNotFoundException異常。

是不是?所以你永遠不會得到編譯的內部類。如果你能克服這個問題

那麼你也可以擴展內部類:)。