繁体   English   中英

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

[英]Calling abstract methods in a superclass constructor

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

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

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

在我的代码中,我在SuperClass构造函数中具有抽象方法,因此您当然会理解该问题:Super类可以:

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

但是,超类构造函数几乎不知道它还需要info3和info4,它们在super()行下面的行中声明。

我一直在尝试让超类构造函数在执行该方法之前必须回溯并从子类收集信息的方式,但是我什么也没想到。

该方法也不需要参数,因为所有子类的抽象方法的参数都不相同。

那些经验丰富的人,我该如何解决?

经过一番谷歌搜索,似乎与此有关: 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;
}

}

最后,我想说声谢谢大家,感谢您抽出宝贵的时间阅读和帮助一个家伙。 我真的很感激。 希望当其他人遇到类似问题时,他们会偶然发现这一问题。

多谢你们!

您面临的问题是,当您从基类调用abstract(或任何重写)方法时,子类实例的构造不完整。 确保对象实例完全构造的唯一方法是完成其构造函数。

解决问题的一种方法是仅将构造函数用于实例的构造,而将(动态)初始化留给方法。 在这种情况下,您可以使用以下方法:

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方法中,您可以调用抽象方法,并确保正确构造了完整的对象实例。

@rsp建议的显式init()方法的替代方法是延迟计算其他结果。 例如

public int getValue() {
   if (value == 0) { // some constant or value that means not-computed yet
      value = blah*foo*bar;
   }
   return value;
}

另外,这并不像您对value()的计算会花费很多时间。 只是总是重新计算它。 30年前,您已经缓存了所有这些东西。 缓存会创建对象为null或陈旧的错误。 或子类。 :-)处理器现在速度更快,重新计算通常更简单,有时甚至更快。

查看提交的代码示例,没有迹象表明在基类中使用了abstract方法。 我希望这是为了简化。 否则,将该方法定义为抽象是没有意义的。

若要在由子类计算的基类中缓存值,则不应使用构造函数。 在子类的构造函数有机会为其传递数据之前调用该方法,从而产生您所观察到的效果。

相反,我将为抽象方法定义一个伴随方法,该方法将检查值是否已缓存,如果不缓存,则进行检查。 考虑以下示例:

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

暂无
暂无

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM