2011-04-16 57 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异常。

是不是?所以你永远不会得到编译的内部类。如果你能克服这个问题

那么你也可以扩展内部类:)。