Недавно я потратил немало минут на отладку проблемы в производственном коде, который в итоге оказался вызванным классом, вызывающим абстрактный метод в его конструкторе, и реализация этого класса в подклассе пыталась использовать поле подкласса, которое еще не был инициализирован (пример, иллюстрирующий, что эта точка приведена ниже)
Во время исследования этого вопроса я наткнулся на этот вопрос и был заинтригован ответом Джона Скита:
В общем, это плохая идея вызывать неконкретный метод внутри конструктора именно по этой причине - тело конструктора подкласса еще не будет выполнено, поэтому вы эффективно вызываете метод в среде, которая hasn ' t была полностью инициализирована.
Мне интересно, существует ли законная причина вызывать неконфиденциальный или абстрактный метод из конструктора? Или это почти всегда является признаком плохого дизайна?
Пример
public class SSCCE {
static abstract class A {
public A() {
method(); // Not good; field arr in B will be null at this point!
}
abstract void method();
}
static class B extends A {
final String[] arr = new String[] { "foo", "bar" };
public B() {
super();
System.out.println("In B(): " + Arrays.toString(arr));
}
void method() {
System.out.println("In method(): " + Arrays.toString(arr));
}
}
public static void main(String[] args) {
new B().method();
}
}
И вот ожидаемый результат:
В методе(): null
В B(): [foo, bar]
В методе(): [foo, bar]
Проблема, конечно, в том, что в первом вызове method()
поле arr
имеет значение null, поскольку оно еще не инициализировано.