При вызове переопределенного метода из конструкторов
Проще говоря, это неправильно, потому что это излишне открывает возможности для МНОГО ошибок. Когда вызывается @Override
, состояние объекта может быть непоследовательным и / или неполным.
Цитата из Effective Java 2nd Edition, Item 17: Дизайн и документ для наследования, или же запретить его :
Существует еще несколько ограничений, которым должен подчиняться класс, чтобы разрешить наследование. Конструкторы не должны вызывать переопределяемые методы , прямо или косвенно. Если вы нарушите это правило, произойдет сбой программы. Конструктор суперкласса выполняется перед конструктором подкласса, поэтому метод переопределения в подклассе будет вызван до запуска конструктора подкласса. Если переопределяющий метод зависит от какой-либо инициализации, выполняемой конструктором подкласса, метод не будет работать должным образом.
Вот пример для иллюстрации:
public class ConstructorCallsOverride {
public static void main(String[] args) {
abstract class Base {
Base() {
overrideMe();
}
abstract void overrideMe();
}
class Child extends Base {
final int x;
Child(int x) {
this.x = x;
}
@Override
void overrideMe() {
System.out.println(x);
}
}
new Child(42); // prints "0"
}
}
Здесь, когда конструктор Base
вызывает overrideMe
, Child
не завершил инициализацию final int x
, и метод получает неправильное значение. Это почти наверняка приведет к ошибкам и ошибкам.
Похожие вопросы
Смотри также
На строительство объекта с множеством параметров
Конструкторы с множеством параметров могут привести к плохой читаемости, и существуют лучшие альтернативы.
Вот цитата из Effective Java 2nd Edition, Item 2: Рассмотрим шаблон компоновщика, когда сталкиваемся со многими параметрами конструктора :
Традиционно программисты использовали шаблон телескопического конструктора , в котором вы предоставляете конструктору только необходимые параметры, другой - с одним необязательным параметром, третий - с двумя дополнительными параметрами и т. Д. .
Шаблон телескопического конструктора выглядит примерно так:
public class Telescope {
final String name;
final int levels;
final boolean isAdjustable;
public Telescope(String name) {
this(name, 5);
}
public Telescope(String name, int levels) {
this(name, levels, false);
}
public Telescope(String name, int levels, boolean isAdjustable) {
this.name = name;
this.levels = levels;
this.isAdjustable = isAdjustable;
}
}
И теперь вы можете сделать любое из следующего:
new Telescope("X/1999");
new Telescope("X/1999", 13);
new Telescope("X/1999", 13, true);
Однако в настоящее время вы не можете установить только name
и isAdjustable
, и оставить levels
по умолчанию. Вы можете предоставить больше перегрузок конструктора, но очевидно, что число будет увеличиваться по мере увеличения количества параметров, и у вас может даже быть несколько аргументов boolean
и int
, что действительно может испортить ситуацию.
Как видите, это не очень приятный для написания образец, и даже менее приятный в использовании (что означает здесь "правда"? Что такое 13?).
Bloch рекомендует использовать шаблон построителя, который позволит вам написать что-то вроде этого:
Telescope telly = new Telescope.Builder("X/1999").setAdjustable(true).build();
Обратите внимание, что теперь параметры названы, и вы можете устанавливать их в любом порядке, в котором вы хотите, и вы можете пропустить те, которые вы хотите оставить со значениями по умолчанию. Это, безусловно, намного лучше, чем телескопические конструкторы, особенно когда существует огромное количество параметров, принадлежащих многим из тех же типов.
Смотри также
Похожие вопросы