为什么我不能这样做/是否有解决方法来完成此任务:
package myPackage;
public class A {
public class B {
}
}
Run Code Online (Sandbox Code Playgroud)
package myPackage;
import myPackage.A.B;
public class C extends B {
}
Run Code Online (Sandbox Code Playgroud)
package myPackage;
public class Main {
public static void main(String[] args) {
A myA = new A();
C myC = myA.new C();
}
}
Run Code Online (Sandbox Code Playgroud)
两个编译错误是
在public class C extends B,No enclosing instance of type A is available due to some intermediate constructor invocation
在C myC = myA.new C();,A.C cannot be resolved to a type
坦率地说,我认为概念是合理的:我想制作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静态并让它的构造函数接受它的封闭实例,将它保存在受保护的变量中以便在其子代中访问,但这不如RealSkeptic接受的答案那么优雅)
删除.请参见底部的编辑.
所以,如果你的回答表明我做了上述其中一个,那么这不是这个问题的答案,即使它可能对其他人有用.
如果您的回答是"这只是Java语言的一个缺陷,那么您根本无法实现这个概念性的想法",这是一个好的答案,您应该发布它.但是只是一个警告:如果您错了,我会推迟将您的答案标记为已接受.如果这是您的答案,我将非常感谢您解释为什么对该语言的这种限制(因为这是该问题的标题).
感谢您的帮助.
编辑:JoshuaTaylor的回答提出了一个有效的选择:你可以匿名扩展B.并避免像在RealSkeptic接受的答案中那样编写构造函数.我最初放弃了这个想法,因为它不允许你通过"A.this"访问C的封闭A实例.但是,我已经知道C没有A的封闭实例,除非它在A的定义中作为嵌套类特别定义.所以请注意:以下解决方案都不允许您通过在C方法中写"A.this"来访问包含C的祖先B的A的封闭实例.类只能使用".this"来访问它们的类型具体嵌套在.但是,如果B具有访问A的封闭实例的功能,则需要通过JoshuaTaylor方法的匿名类或通过RealSkeptic方法的任何其他类.
Rea*_*tic 11
好吧,它可以完成,但你必须记住,每个构造函数都需要显式或隐式地调用它的超级构造函数.这就是为什么你得到"由于某些中间构造函数调用而没有A类的封闭实例"错误.C'no-args构造函数试图隐式调用B'no-args构造函数,如果没有一个,它就不能这样做A.
所以你修复你的C:
public class C extends B {
public C(A enclosing) {
enclosing.super();
}
}
Run Code Online (Sandbox Code Playgroud)
然后你可以C使用以下方法创建一个新的:
A myA = new A();
C myC = new C(myA);
Run Code Online (Sandbox Code Playgroud)
答案中的问题
@Andi特纳问道:
如果你明确地将A传递给C的构造函数,那么C现在不能是静态的,并且在C中使用A作为"普通旧"成员变量来调用所需的方法吗?
应该注意的是,C既不是静态的也不是内部的.它是一个单独的公共类,它扩展了一个内部类B.C的作者可能不知道B类的实现,所以它不知道使用A的方法是什么,也不能访问任何私有成员A,因为C不是A的成员但是B确实如此,并且B需要A实例.另一种方法是组合而不是继承(其中C持有B实例并将操作委托给它),但是如果它想要创建该B实例而不是将其传递到内部,它仍然需要一个A实例,尽管它会使用enclosing.new B而不是enclosing.super.
@rajuGT问:
C是个体吗?如果是这样,为什么它需要A对象?在这种情况下,myA和myC之间的联系是什么?
是的,C是一个单独的实体.对于任何自己的方法都不需要A. 但是如果它试图调用(或继承并且不覆盖)B中涉及访问A的方法 - 则B的实现需要A.当然,任何B的实例都需要引用A even如果它实际上没有使用它.之间的关联myA和myC是是myA是立即包围实例myC相对于B.该术语取自JLS第8.1.3节:
对于每一个超类
S的C其本身是一个直接的内部类的类或接口的SO,有的一个实例SO与相关联的i,被称为的立即封闭实例i相对于S.当通过显式构造函数调用语句调用超类构造函数时,确定对象的直接封闭实例(如果有的话)(§8.8.7.1)
官方参考此用法
这种用法称为限定的超类构造函数调用语句,在JLS的8.8.7.1节 - 显式构造函数调用中提到.
超类构造函数调用以关键字
super(可能以显式类型参数开头)或主 表达式或ExpressionName开头.它们用于调用直接超类的构造函数.他们进一步分裂:
非限定的超类构造函数调用以关键字
super开头(可能以显式类型参数开头).合格的超类构造函数调用以Primary 表达式或ExpressionName开头.它们允许子类构造函数显式指定新创建的对象关于直接超类(第8.1.3节)的直接封闭实例.当超类是内部类时,这可能是必要的.
在该部分的末尾,您可以找到显式构造函数调用语句的示例,包括此用法.
| 归档时间: |
|
| 查看次数: |
1777 次 |
| 最近记录: |