我在super的构造函数中有一个抽象方法调用。我遇到错误“构造函数调用必须是构造函数中的第一个语句。”因为在调用super的构造函数之前,我需要在子类中初始化一些状态。
我知道构造函数调用必须是第一个..但它让我遇到了一些问题。
我的超类中有一个抽象方法,所有子类都实现了它们自己。 但是子类构造函数需要在运行抽象方法之前必须处理的参数。
在我的代码中,我在SuperClass构造函数中有抽象方法,所以你当然会理解这个问题: 超级课程:
但Superclass构造函数很少知道它还需要info3和info4,它们在下面的行上声明 super() - line。
我一直试图想办法让Superclass构造函数必须返回并从子类中收集信息 它执行方法,但我没有想到任何东西。
此方法也不能要求参数,因为所有子类的抽象方法的参数都不同。
那些有经验的人,我该如何解决这个问题?
经过一些谷歌搜索,似乎与此有关: http://webcache.googleusercontent.co...s-constructor/
但仍然是新手,所以很难坚持下去...... 如果我可以在处理子类构造函数后使用super(),我觉得我可以避免所有这些麻烦。
请求代码:
abstract public class Prylar {
abstract public Integer value();
private String itemName;
private Person owner;
public Prylar(Person thisOwner, String iN){
owner = thisOwner;
itemName = iN;
value = value();
}
public class Smycken extends Prylar{
private int antalStenar;
private boolean guldEllerSilver;
private int value;
public Smycken (Person who, String n, int aS, boolean material){
super(who,n);
antalStenar = aS;
guldEllerSilver = material;
}
public Integer value() {
if (guldEllerSilver){
value = 2000;
}
else{
value= 700;}
value += (500*antalStenar);
return value;
}
}
我只是想结束这一点,谢谢大家花时间阅读并帮助一个人。对此,我真的非常感激。希望当其他人遇到类似的问题时,他们会偶然发现这个问题。
谢谢你们!
答案 0 :(得分:2)
您遇到的问题是,当您从基类调用abstract(或任何overriden)方法时,子类实例不会完全构造。确保对象实例完全构造的唯一方法是完成其构造函数。
解决问题的一种方法是仅使用构造函数构造实例并将(动态)初始化保留给方法。在这种情况下,您可以使用以下方法:
private boolean initialized = false;
public synchronized boolean init() {
if (!initialized) {
// allocate resources, call abstract method(s)
initialized = true;
}
return initialized;
}
public synchronized void cleanup() {
if (initialized) {
// free resources, call abstract method(s)
initialized = false;
}
}
调用代码可以明确调用init()
和cleanup()
方法,或者将调用init()
保留为模式,如下所示:
public void doSomething() {
if (init()) {
// go!
}
}
在init方法中,您可以调用抽象方法,并确保正确构造完整的对象实例。
答案 1 :(得分:1)
@rsp建议的显式init()方法的替代方法是懒惰地计算其他结果。 e.g。
public int getValue() {
if (value == 0) { // some constant or value that means not-computed yet
value = blah*foo*bar;
}
return value;
}
或者,它不像你对value()的计算需要花费很多时间。只是总是重新计算它。 30年前,你要缓存所有这些东西。缓存会创建对象为null或过时的错误。或子类。 :-)处理器现在更快,通常更简单,偶尔更快,只需重新计算。
答案 2 :(得分:0)
查看提交的代码示例,没有迹象表明在基类中使用了抽象方法。我希望这是为了简化。否则,将该方法定义为抽象是没有意义的。
要将值缓存在由子类计算的基类中,不应使用构造函数。在子类的构造函数有机会为其传递数据之前调用该方法,从而产生您观察到的效果。
相反,我会为抽象方法定义一个伴随方法,它会检查值是否被缓存,如果不进行缓存。 考虑这个例子:
public abstract class Base {
private final String name;
private BigInteger cachedValue;
public Base(String name) {
this.name = name;
}
public BigInteger calculate() {
final BigInteger one = BigInteger.ONE;
//do the calculation involving `value` call
return value().multiply(one);
}
protected abstract BigInteger doComplexCalculation();
protected BigInteger value () {
if (cachedValue == null) {
this.cachedValue = doComplexCalculation();
}
return this.cachedValue;
}
}
此案例的子类示例:
public class SubClass extends Base {
private int number;
public SubClass(String name, int number) {
super(name);
this.number = number;
}
@Override
protected BigInteger doComplexCalculation() {
//do calculations and return a result which will be cached by the base class
return BigInteger.valueOf(number);
}
//The cached value can then be accessed by other methods
//through the use of protected `value` method call.
}