我无法创建B-Object,但为什么?
public class AFactory {
public int currentRange;
private abstract class A {
protected final Object range = currentRange;
public int congreteRange = 28;
}
public class B extends A {
public int congreteRange = 42;
}
synchronized A createNew(Class<? extends A> clazz) throws Exception {
// EDIT: there is accessible default constructor
currentRange = clazz.newInstance().congreteRange;
return clazz.newInstance();
}
public static void main(String[] args) throws Exception {
AFactory factory = new AFactory();
System.out.println(factory.createNew(B.class).range);
}
}
例外是:
Exception in thread "main" java.lang.InstantiationException: AFactory$B
at java.lang.Class.newInstance0(Class.java:357)
at java.lang.Class.newInstance(Class.java:325)
at AFactory.createNew(AFactory.java:15)
at AFactory.main(AFactory.java:21)
答案 0 :(得分:2)
问题是您正在尝试实例化内部类,您只能在外部类的实例上访问它。内部类的构造函数采用封闭类的隐式隐藏instance
。您可以通过分析这个简单类的字节代码来看到它:
public class Demo {
class Test {
}
}
现在,编译代码:
javac Demo.java
这将创建两个类文件:
Demo.class
Demo$Test.class
运行以下命令以查看Demo$Test.class
的字节代码:
javap -c . Demo$Test
您将获得以下结果:
class Demo$Test {
final Demo this$0;
Demo$Test(Demo);
Code:
0: aload_0
1: aload_1
2: putfield #1 // Field this$0:LDemo;
5: aload_0
6: invokespecial #2 // Method java/lang/Object."<init>":
()V
9: return
}
那么,你看到该类的构造函数?它需要Demo
作为参数。所以,没有0-arg构造函数。
但是,如果你创建内部类static
,它就可以工作,因为那时你不需要任何封闭类的实例来调用内部类构造函数。
使用static
内部类 - 备选:
public class AFactory {
public static int currentRange;
private static abstract class A {
protected final Object range = AFactory.currentRange;
}
public static class B extends A {
public int congreteRange = 42;
}
synchronized A createNew(Class<? extends B> clazz) throws Exception {
currentRange = clazz.newInstance().congreteRange;
return clazz.newInstance();
}
public static void main(String[] args) throws Exception {
AFactory factory = new AFactory();
System.out.println(factory.createNew(B.class).range);
}
}
使用非static
内部类 - 最终代码:
如果你不想让它们static
,那么你必须首先创建一个封闭类的实例。并将其传递给内部类的构造函数。要获取内部类的构造函数,可以使用Class#getDeclaredConstructor
方法。
现在,您必须修改工厂方法以将Constructor
作为参数。像这样修改你的代码:
public class AFactory {
public int currentRange;
private abstract class A {
protected final Object range = currentRange;
}
public class B extends A {
public int congreteRange = 42;
}
synchronized A createNew(Constructor<? extends A> ctor) throws Exception {
// Pass `this` as argument to constructor.
// `this` is reference to current enclosing instance
return ctor.newInstance(this);
}
public static void main(String[] args) throws Exception {
AFactory factory = new AFactory();
// Get constructor of the class with `AFactory` as parameter
Class<B> bClazz = B.class;
Constructor<B> ctor = bClazz.getDeclaredConstructor(AFactory.class);
System.out.println(factory.createNew(ctor));
}
}
答案 1 :(得分:1)
您无法创建A,因为您将clazz
定义为扩展B
且A
不扩展B
的类型 - 反之亦然( B
扩展了A
)。
您应该将createNew
签名更改为:
synchronized A createNew(Class<? extends A> clazz) throws Exception
答案 2 :(得分:-1)
将您的类和变量更改为静态。
public class AFactory {
public static int currentRange;
private static abstract class A {
protected final Object range = currentRange;
}
public static class B extends A {
public int congreteRange = 42;
}
synchronized A createNew(Class<? extends B> clazz) throws Exception {
currentRange = clazz.newInstance().congreteRange;
return clazz.newInstance();
}
public static void main(String[] args) throws Exception {
AFactory factory = new AFactory();
System.out.println(factory.createNew(B.class).range);
}
}
,输出 42 。