为什么我不能这样做/是否有解决方法来实现这一点:
package myPackage;
public class A {
public class B {
}
}
package myPackage;
import myPackage.A.B;
public class C extends B {
}
package myPackage;
public class Main {
public static void main(String[] args) {
A myA = new A();
C myC = myA.new C();
}
}
这两个编译错误是
>
OnC myC=myA。新C()
,
A。C无法解析为类型
坦率地说,我认为这个概念是合理的:我想创建B的一个子类,这样当我为a创建B时,我可以选择使其具有B中的功能或C中的功能。
我不想要的四种变通方法/解决方案,以及为什么我不想要它们:
>
"解决方案:将C放在A中。"我不希望这样,因为如果我无法修改A. java的代码怎么办(有些应用程序有此限制)?如果A是另一个API的一部分怎么办?然后我必须为C创建一个新文件,就像我在这里所做的那样。
“解决方案:将C放在扩展a的类D中。”我不希望这样,因为这样C仅限于在D类型的实例上实例化。我想创建一个扩展B的类,该类可以在a类型的所有实例上实例化(有些应用程序需要这样做)。因此,我需要C不要像我在这里做的那样被另一个类包围。
(作为问题编辑添加-请参阅JoshuaTaylor对代码示例的回答)“解决方案:将B设为静态。”我不希望这样,因为如果B中的功能需要访问其封闭的a实例(有一些应用程序需要这样做),该怎么办?因此,我需要B不是静态的,就像我在这里做的那样。(第二个问题编辑:您可以将B设为静态,并让其构造函数接受其封闭实例,将其保存在受保护的变量中,以便在其子对象中进行访问,但这没有Real怀疑论者所接受的答案那么优雅)
已删除。请参阅底部的编辑。
所以,如果你的回答暗示我做了上述的一个,那就不是这个问题的答案,即使它可能对其他人有用。
如果你的答案是“这只是Java语言的一个缺陷,你根本无法实现这个概念性的想法”,那么这是一个不错的答案,你应该发布它。不过,这只是一个警告:如果你错了,我会推迟将你的答案标记为已接受。如果这是你的答案,如果你能解释一下为什么对语言有这样的限制(因为这是这个问题的标题),我将不胜感激。
谢谢你的帮助。
编辑:JoshuaTaylor的答案提出了一个有效的选项:您可以匿名扩展B,避免像Real怀疑论者的公认答案那样编写构造函数。我最初放弃了这个想法,因为它不允许您通过“A.this”访问C的封闭实例。然而,我后来了解到,C没有A的封闭实例,除非它在A的定义中被明确定义为嵌套类。因此请注意:下面的解决方案都不允许您通过在C的方法中写入“A.this”来访问A的封闭实例,该实例封闭了C的祖先B。类只能使用“.this”来访问它们专门嵌套的类型。然而,如果B具有访问A封闭实例的功能,则需要通过JoshuaTaylor的方法创建匿名类,或者通过Real怀疑论者的方法创建任何其他类。
更新:你已经提到你不想要第一个解决方案,但是这个问题的措辞可能会让那些愿意让内部类保持静态的人找到它,所以我会留下这个,希望它对他们有用。你确切问题的更合适的答案在这个答案的第二部分。
可以,但内部类必须是静态的,因为如果不是静态的,则内部类的每个实例都有一个对外部类的封闭实例的引用。静态嵌套类没有该引用,您可以自由扩展它。
public class Outer {
public static class Inner {
}
}
public class InnerExtension extends Outer.Inner {
}
package test;
public class Outer {
public class Inner {
public String getFoo() {
return "original foo";
}
}
}
package test;
public class Extender {
public static void main(String[] args) {
// An instance of outer to work with
Outer outer = new Outer();
// An instance of Outer.Inner
Outer.Inner inner = outer.new Inner();
// An instance of an anonymous *subclass* of Outer.Inner
Outer.Inner innerExt = outer.new Inner() {
@Override
public String getFoo() {
return "subclass foo";
}
};
System.out.println("inner's class: "+inner.getClass());
System.out.println("inner's foo: "+inner.getFoo());
System.out.println();
System.out.println("innerExt's class: "+innerExt.getClass());
System.out.println("innerExt's foo: "+innerExt.getFoo());
}
}
inner's class: class test.Outer$Inner
inner's foo: original foo
innerExt's class: class test.Extender$1
innerExt's foo: subclass foo
当然,这是可以做到的,但你必须记住,每个构造函数都需要显式或隐式调用其超级构造函数。这就是为什么会出现“由于某些中间构造函数调用,没有可用的A型封闭实例”错误
所以你把你的C修正为:
public class C extends B {
public C(A enclosing) {
enclosing.super();
}
}
然后您可以使用以下命令创建一个新的C
:
A myA = new A();
C myC = new C(myA);
对评论中问题的回答
>
@安迪·特纳问道:
如果您将A显式传递给C的构造函数,那么C现在不能是静态的,并且在C中将A作为调用所需方法的“普通旧”成员变量吗?
应该注意的是,C既不是静态的,也不是内部类。它是一个扩展内部类B的单个公共类。C的作者可能不知道类B的实现,因此它不知道使用A的方法是什么,也不能访问A的任何私有成员,因为C不是A的成员,但B是,B需要A实例。另一种方法是组合而不是继承(C持有一个B实例并将操作委托给它),但如果它想创建该B实例而不是将其传递到内部,它仍然需要一个a实例,尽管它将使用封闭。新的B,而不是封闭的。super。
@rajuGT问:
C是一个单独的实体吗?如果是这样,为什么它需要一个对象?在这种情况下,myA和myC之间有什么联系?
是的,C是一个单独的实体。它不需要为自己的任何方法创建一个。但是,如果它试图从B调用(或继承但不重写)涉及访问A的方法,那么B的实现需要A。当然,形式上,任何B实例都需要引用A,即使它实际上没有使用它。myA和myC之间的关联是,myA是myC相对于B的直接封闭实例。该术语取自JLS第8.1.3节:
对于C
的每个超类S
,它本身就是类或接口SO
的直接内部类,SO
的实例与i
相关联,称为i
的立即封闭实例相对于S
。对象相对于其类的直接超类(如果有)的立即封闭实例是在通过显式构造函数调用语句调用超类构造函数时确定的(§8.8.7.1)
此用法的官方参考
这种用法称为限定的超类构造函数调用语句,并在JLS第8.8.7.1节-显式构造函数调用中提到。
超类构造函数调用从关键字super(可能以显式类型参数开头)或主表达式或表达式名开始。它们用于调用直接超类的构造函数。它们进一步划分为:
>
不合格的超类构造函数调用以关键字Super
开头(可能以显式类型参数开头)。
限定的超类构造函数调用以主表达式或表达式名开始。它们允许子类构造函数显式指定新创建的对象相对于直接超类的立即封闭实例(§8.1.3)。当超类是内部类时,这可能是必要的。
在该部分的末尾,您可以找到显式构造函数调用语句的示例,包括这种用法。
(我一直在重读那个问题标题,思考它看起来有多荒谬,但我向你保证,这是对问题的最佳描述,我有一个实际的应用程序,其中这是最好的结构。我发誓我没有疯。) 考虑以下内容。每个块都是一个单独的文件: 注意,enclosinstance业务是为了解决涉及中间构造函数调用的问题。请参阅“为什么外部类不能扩展内部类?”。 我希望输出为“2”。但是相反,我在System.out.println(a.this.I)
问题内容: 在下面显示的代码片段中,内部类本身继承了外部类。 方法中的唯一语句(最后一个片段)将值分配给类的私有字段,然后调用该方法。 该方法会导致另一个字符串- 要设置的私人领域中的类调用之前的方法延长。 因此,方法中的以下两个语句: 应该显示 另一个价值 另一个价值 但是他们显示 初始值 初始值 为什么会这样? 问题答案: 方法和领域都是。因此,其他子类(包括子类)均无法访问它们。它们不是继承
问题内容: 我想知道为什么在Java语言中a 不能扩展。 我不是在谈论一个延伸的(这不能做,因为Java没有多重继承,而Š隐含延长),但一类的以只添加额外的方法,而不是额外的枚举值。 就像是: 要这样使用: 因此,有人可以对此限制提供理由(或将我指向正确的JLS部分)吗? 问题答案: 我认为 他们这样做 的答案来自以下问题: 在您的示例中,如何实例化MyClass?用户永远不会(通过)显式实例化枚
问题内容: 因此,我们大多数人都知道 如何 从内部类访问外部类。用这些词进行搜索会给出关于该主题的大量回答问题。但是我想知道的是为什么语法是这样。 例: 为什么呢?看起来是A类的静态字段,但是… 感到困惑 如果这是重复的话,请原谅我。就像我说的那样,用这些词进行搜索会给出操作答案。 问题答案: 为什么这样做呢?真的,只是因为它的方式。它行之有效,从某种意义上讲,并且不需要花哨的语法来完成这项工作。
为什么<code>test
问题内容: Java教程说,由于内部类与封闭类的实例相关联,所以它(内部类)本身不能定义任何静态成员。 对我来说很有趣,为什么内部类不能声明静态成员,例如某个字段,该内部类的实例可能会与同一内部类的其他实例共享这些成员?这仅仅是Java中必须被视为理所当然的事情的实现吗? 问题答案: 基本上只是一个任意决定。我们没有理由也 不可能 得到支持,但还算不上什么好的理由 来 支持它。只需在外部类中声明静