Вызов абстрактных методов в конструкторе суперкласса - PullRequest
0 голосов
/ 07 декабря 2011

У меня есть абстрактный вызов метода в конструкторе моего супер. Я сталкиваюсь с ошибкой «вызов конструктора должен быть первым оператором в конструкторе». потому что мне нужно инициализировать некоторое состояние в моих подклассах перед вызовом конструктора супер.

Я понимаю, что вызов конструктора должен быть первым ... но это вызывает у меня некоторые проблемы.

В моем суперклассе есть абстрактный метод, который все подклассы реализуют сами. Но конструктор подкласса требует аргументов, которые должны быть обработаны до запуска абстрактного метода.

В моем коде у меня есть абстрактный метод в конструкторе SuperClass, поэтому вы, конечно, поймете проблему: Супер класс делает:

  1. Получить info1 и info2, используя super (i1, i2)
  2. Выполняет абстрактный метод через подкласс

Но конструктор Superclass мало что знал, что ему также нужны info3 и info4, которые объявлены в строках ниже супер () - строка.

Я пытался придумать, как конструктор Суперкласса должен вернуться и собрать информацию из подкласса, прежде чем он выполняет метод, но я ни о чем не думал.

Кроме того, метод не может требовать аргументов, поскольку аргументы различаются для всех абстрактных методов всех подклассов.

Те из вас, кто опытен, как мне обойти это?

После некоторого поиска в Google, похоже, это связано с этим: http://webcache.googleusercontent.co. .. s-конструктор /

Но все еще новичок, так что трудно удержаться на .. Я чувствую, что мог бы избежать всех этих проблем, если бы мог просто использовать 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 ]

2 голосов
/ 07 декабря 2011

Проблема, с которой вы сталкиваетесь, заключается в том, что экземпляр подкласса не создается полностью, когда вы вызываете абстрактный (или любой переопределенный) метод из базового класса. Единственный способ убедиться, что экземпляр объекта построен полностью, - это завершить его конструктор.

Один из способов решения вашей проблемы - использовать конструкторы только для конструирования экземпляров и оставить (динамическую) инициализацию для метода. В таких случаях вы можете использовать такие методы, как:

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 голос
/ 07 декабря 2011

Альтернативой явному методу init (), предложенному @rsp, является ленивый расчет этих других результатов. например,

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

В качестве альтернативы, это не похоже на то, как ваш расчет значения () занимает много времени. Просто всегда пересчитываю это. 30 лет назад вы бы все это кешировали. Кэширование создает ошибки с нулевыми или устаревшими объектами. Или подклассы. :-) Процессоры теперь стали быстрее, часто проще, а иногда и быстрее, просто пересчитать.

0 голосов
/ 31 июля 2016

Глядя на представленный пример кода, нет никаких признаков того, что абстрактный метод используется в базовом классе.Я надеюсь, что это ради упрощения.В противном случае не имеет смысла определять этот метод как абстрактный.

Чтобы кэшировать значение в базовом классе, которое вычисляется подклассом, вы не должны использовать конструктор.Метод вызывается до того, как конструктор подкласса имеет возможность передать данные для него, вызывая наблюдаемый вами эффект.

Вместо этого я бы определил сопутствующий метод для абстрактного, который будет проверять, является ли значениекэшировать и если не делать кэширование.Рассмотрим этот пример:

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.
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...