Как изменить частное поле из абстрактного класса в Java?
-
10-07-2019 - |
Вопрос
Есть абстрактный класс:
public abstract class AbstractAny {
private long period;
public void doSomething() {
// blah blah blah
period = someHardcodedValue;
// blah blah blah
}
}
Я не хочу менять источник абстрактного класса, но мне нужно добавить некоторую гибкость в настройке периода поля. Можно ли изменить значение периода поля из переопределенного метода? Как например:
public class ConcreteSome extends AbstractAny{
@Override
public void doSomething() {
try {
Field p = super.getClass().getDeclaredField("period");
p.setAccessible(true);
p.setLong(this, 10L);
} catch (SecurityException e) {
throw new RuntimeException(e);
} catch (NoSuchFieldException e) {
throw new RuntimeException(e);
} catch (IllegalArgumentException e) {
throw new RuntimeException(e);
} catch (IllegalAccessException e) {
throw new RuntimeException(e);
}
}
}
Когда я пытаюсь запустить этот код, super.getClass (). getDeclaredField (" period ")
выбрасывает java.lang.NoSuchFieldException: period
Решение
Вам нужен getClass (). getSuperclass ()
, чтобы получить суперкласс, а не super.getClass ()
.
Однако я действительно не рекомендую делать это. Вы в основном разрушаете инкапсуляцию абстрактного класса. Если абстрактный класс не обеспечивает достаточной гибкости для своих потомков, его следует исправить - обходить его просто напрашивается на неприятности. Что, если какой-либо другой член абстрактного класса должен быть изменен всякий раз, когда это происходит? Весь смысл наличия частного состояния состоит в том, что класс может защитить свои собственные данные. Подобное отражение - это действительно уродливый хак, который должен быть абсолютно последним .
Другие советы
Я с Джоном Скитом. В конечном счете, проще изменить исходный код суперкласса, чтобы либо сделать это поле защищенным, либо делегировать мутацию переопределяемому методу. Использование отражения для изменения значения теперь работает нормально, но оно не очень хорошо масштабируется с точки зрения обслуживания с течением времени.
ConcreteSome не расширяет абстрактный класс AbstractAny.
Попробуйте это
public class ConcreteSome {
@Override
public void doSomething() {
Class<?> clazz = getClass().getSuperclass();
System.out.println(clazz);
Field p = clazz.getDeclaredField("period");
...
должен вернуть java.lang.Object