Подобная проблема, по-моему описывалась Блохом, но я изложу ее на русском и со своей стороны. Имеем родительский класс с полем, значение которого инициализируется в конструкторе (логика обычно простая). По правилам хорошего тона эта логика вынесена в отдельный метод. Поле после инициализации больше не используется для записи и поэтому final.
Спустя какое-то время появляется наследник класса у которого логика инициализации поля field другая. Для этого модификатор доступа меняется на protected, чтобы дать возможность наследнику заложить туда свою логику. Итак, получаем:
Спустя какое-то время появляется наследник класса у которого логика инициализации поля field другая. Для этого модификатор доступа меняется на protected, чтобы дать возможность наследнику заложить туда свою логику. Итак, получаем:
- static class Parent {
- Parent() {
- field = createField();
- }
- return "Parent-impl";
- }
- return getClass().getSimpleName() + field;
- }
- }
- static class Child extends Parent {
- leftPart = left;
- rightPart = right;
- }
- return leftPart + rightPart;
- }
- }
По результатам кажется что main должен вернуть ABCD. Однако это не так. Проблема в том, что в логике переопределенного метода createField() не должны участвовать состояния как наследника, так и родителя. Проще говоря можно использовать только константы (statiс final), хотя и с ними надо быть осторожным. Почему? Дело в том, что на момент вызова метода поля его + родительские поля создаваемого экземпляра еще не до конца созданы. В данном примере в момент вызова Child.createField() поля leftPart и rightPart ещё не проинициализированы (хотя они и final) и равны null.
Как теперь это исправить?
Есть несколько способов, я предпочитаю работать вместо поля с методом и как следствие вынести инициализацию в "ленивую" секцию. Как-то так:
- static class Parent {
- Parent() {
- field = createField();
- }
- return "Parent-impl";
- }
- return field;
- }
- return getClass().getSimpleName() + getField();
- }
- }
- static class Child extends Parent
- {
- leftPart = left;
- rightPart = right;
- }
- protected String getField
- () {
- return leftPart + rightPart;
- }
- }