在超类构造函数中调用抽象方法

时间:2011-12-06 20:05:31

标签: java superclass

我在super的构造函数中有一个抽象方法调用。我遇到错误“构造函数调用必须是构造函数中的第一个语句。”因为在调用super的构造函数之前,我需要在子类中初始化一些状态。

我知道构造函数调用必须是第一个..但它让我遇到了一些问题。

我的超类中有一个抽象方法,所有子类都实现了它们自己。 但是子类构造函数需要在运行抽象方法之前必须处理的参数。

在我的代码中,我在SuperClass构造函数中有抽象方法,所以你当然会理解这个问题: 超级课程:

  1. 使用super(i1,i2)
  2. 获取info1和info2
  3. 通过子类
  4. 执行抽象方法

    但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;
    }
    

    }

    我只是想结束这一点,谢谢大家花时间阅读并帮助一个人。对此,我真的非常感激。希望当其他人遇到类似的问题时,他们会偶然发现这个问题。

    谢谢你们!

3 个答案:

答案 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.
}