代码之家  ›  专栏  ›  技术社区  ›  Boris Pavlović

如何将私有字段与Java中的抽象类进行变异?

  •  2
  • Boris Pavlović  · 技术社区  · 17 年前

    有一个抽象类:

    public abstract class AbstractAny {
      private long period;
    
      public void doSomething() {
        // blah blah blah
        period = someHardcodedValue;
        // blah blah blah
      }
    }
    

    我不想更改抽象类的源代码,但需要在如何设置字段周期方面增加一些灵活性。是否可以从overriden方法更改字段period的值?例如:

    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 回复  |  直到 17 年前
        1
  •  20
  •   Jon Skeet    17 年前

    你需要 getClass().getSuperclass() 得到超类,不是 super.getClass() .

    然而,我 真的? 不要建议这样做。您基本上正在破坏抽象类的封装。如果抽象类没有为它的后代提供足够的灵活性,那么它应该是固定的——绕过它只是在自找麻烦。如果抽象类的某个其他成员在执行此操作时需要进行更改,该怎么办?私有状态的关键在于类能够保护自己的数据。像这样使用反射是一个非常丑陋的黑客行为,应该是绝对的 最后的 度假胜地。

        2
  •  2
  •   matt b    17 年前

    我和乔恩·斯基特在一起。从长远来看,更容易更改超类的源代码,使该字段受到保护,或者将突变委托给可重写的方法。使用反射来更改值现在可以工作了,但是随着时间的推移,它的伸缩性并不是很好。

        3
  •  0
  •   user85421    17 年前

    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