Как изменить частное поле из абстрактного класса в Java? - PullRequest
2 голосов
/ 03 августа 2009

Есть абстрактный класс:

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

Ответы [ 3 ]

20 голосов
/ 03 августа 2009

Вам нужно getClass().getSuperclass(), чтобы получить суперкласс, а не super.getClass().

Однако я действительно не рекомендую делать это. Вы в основном разрушаете инкапсуляцию абстрактного класса. Если абстрактный класс не обеспечивает достаточной гибкости для своих потомков, его следует исправить - обходить его просто напрашивается на неприятности. Что, если какой-либо другой член абстрактного класса должен быть изменен всякий раз, когда это происходит? Весь смысл наличия частного состояния состоит в том, что класс может защитить свои собственные данные. Подобное отражение - это действительно уродливый хак, который должен быть абсолютным последним курортом.

2 голосов
/ 03 августа 2009

Я с Джоном Скитом. В конечном счете, проще изменить исходный код суперкласса, чтобы либо сделать это поле защищенным, либо делегировать мутацию переопределяемому методу. Использование отражения для изменения значения теперь работает нормально, но оно не очень хорошо масштабируется с точки зрения обслуживания с течением времени.

0 голосов
/ 03 августа 2009

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

...