如何从Java中的抽象类变异私有字段?

时间:2009-08-03 13:51:22

标签: java reflection abstract-class private-members

有一个抽象类:

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 个答案:

答案 0 :(得分:20)

您需要getClass().getSuperclass()来获取超类,而不是super.getClass()

但是,我确实不建议这样做。你基本上是在破坏抽象类的封装。如果抽象类没有为其后代提供足够的灵活性,那么它应该是固定的 - 绕过它只是在寻找麻烦。如果抽象类的其他成员需要在这个时候更改,该怎么办?拥有私有状态的全部意义在于,班级能够保护自己的数据。使用这样的反射是一个非常丑陋的黑客应该是一个绝对的最后度假胜地。

答案 1 :(得分:2)

我和Jon Skeet在一起。从长远来看,更容易将超类的源代码更改为使该字段受保护或将变异委托给可覆盖的方法。使用反射来改变值现在可以正常工作,但是随着时间的推移,它不能很好地扩展。

答案 2 :(得分:0)

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