Java - как вызвать другой super() в соответствии с аргументом конструктора наследования класса?

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

Это пример кода для упрощения. Son(int) вызовет super(int,boolean) на основе значения int.

class Base {
  ...
  public Base (int num, boolean boo2) { ...}
  ...
}

class Son extends Base {
  ...
  public Son (int num) {
    if (num > 17)
       super(num, true);
    else
      super(num , false);
  }
  ...
}

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

Ценю твою помощь.


person Oron    schedule 08.01.2014    source источник
comment
Тест с super(num, num > 17);   -  person higuaro    schedule 08.01.2014
comment
У вас есть два или один супер конструктор?   -  person thiago.lenz    schedule 08.01.2014
comment
Подумайте о редизайне. Предпочитайте композицию наследованию.   -  person Sotirios Delimanolis    schedule 08.01.2014
comment
@SotiriosDelimanolis спасибо за это, это не относится к моему конкретному случаю (это действительно наследование, а не композиция), но интересно читать.   -  person Oron    schedule 08.01.2014
comment
И если композиция невозможна, избегайте создания нескольких разновидностей одного и того же класса Эффективный Java № 20: Предпочтение иерархии классов теговым классам   -  person zapl    schedule 08.01.2014


Ответы (7)


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

Class Son extends Base {

  private static boolean getMyBoolean(int num) {
    return num > 17; //or any complex algorithm you need.
  }

  public Son (int num) {
    super(num, getMyBoolean(num));
  }
  ...
}

В противном случае, если отсутствующие аргументы можно вычислить с помощью простого выражения (как в приведенном вами конкретном примере), просто напишите:

Class Son extends Base {
  public Son (int num) {
    super(num, num > 17);
  }
  ...
}
person Sergio    schedule 08.01.2014
comment
Это хорошо работает. Это также соответствует моему реальному случаю, когда найти аргумент немного сложнее, чем (число › 17). В качестве бонуса также становится более понятно, почему это условие используется при вызове super(). - person Oron; 28.03.2014

Я не уверен на 100%, но может ли это сработать?

class Son extends Base {
  ...
  public Son (int num) {
       super(num, (num>17));
  }
  ...
}
person Oscar Pérez    schedule 08.01.2014

Вызов super() должен быть первым оператором в конструкторе. В этом случае вы можете использовать:

class Base {
    public Son(int num) {
        super(num, num > 17);
    }
}

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

class Son extends Base {
    public Son(int num) {
        super(num, calcBoo(num));
    }

    private static boolean calcBoo(int num) {
        if (num > 17)
            return true;
        else
            return false;
    }
}

Другой вариант — скрыть конструктор и добавить статический фабричный метод, который позволит вам выполнять сколь угодно сложную работу перед вызовом суперконструктора:

class Son extends Base {
    private Son(int num, boolean boo) {
        super(num, boo);
    }

    public static Son create(int num) {
        boolean boo;
        // ... statements here ... //
        return new Son(num, boo);
    }
}
person Boann    schedule 08.01.2014
comment
Ваш calcBoo может быть в одной строке.. только return num > 17 - person nachokk; 08.01.2014
comment
@nachokk Я знаю, но я написал это так, чтобы подчеркнуть, что он может делать то, чего не может конструктор: несколько операторов. - person Boann; 08.01.2014

Обратите внимание, что вызов конструктора должен быть первым оператором в конструкторе. Итак, вам необходимо:

public Son (int num) {
   super(num, (num>17));
}

Это сделает то же самое, так как num > 17 будет оцениваться как true или false, и это первый оператор в конструкторе, поэтому он будет скомпилирован.

См. документы:

Вызов конструктора суперкласса должен быть первой строкой в ​​конструкторе подкласса.

person Maroun    schedule 08.01.2014

Первая строка в конструкторе должна быть вызовом super, иначе у вас ее не будет.

Почему бы не подтолкнуть поведение к базовому классу? В любом случае, это был бы лучший способ решить эту проблему.

Таким образом, у вас будет что-то вроде:

Son {
  super(num,17); //in base, you have a "break point" parameter
  ....
}
person Pete B.    schedule 08.01.2014

Из JLS §8.8.7 :

Первый оператор тела конструктора может быть явным вызовом другого конструктора того же класса или прямого суперкласса (§8.8.7.1).

ConstructorBody:
    { ExplicitConstructorInvocationopt BlockStatementsopt }

Вызов super() должен быть первым оператором вашего конструктора. К счастью, в вашем случае есть простой способ сжать его, как уже упоминалось:

public Son(int num) {
    super(num, num > 17);
}
person arshajii    schedule 08.01.2014

Я предполагаю, что вы спрашиваете о требовании, чтобы вызов super был первой строкой в ​​вашем конструкторе.

Вы можете либо использовать простое логическое выражение, подобное другим ответам, либо обобщить решение (в случае, если ваш пример был просто примером) и использовать вызов встроенной функции, который возвращает правильное значение. Вы также можете проверить тернарный оператор.

person Kevin Workman    schedule 08.01.2014