简体   繁体   English

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

[英]How to mutate a private field from the abstract class in Java?

There's an abstract class: 有一个抽象类:

public abstract class AbstractAny {
  private long period;

  public void doSomething() {
    // blah blah blah
    period = someHardcodedValue;
    // blah blah blah
  }
}

I don't want to change the source of the abstract class but need to add some flexibility on how the field period is being set. 我不想更改抽象类的来源,但需要在字段周期的设置方面增加一些灵活性。 Is it possible to change the value of the field period from an overriden method? 是否可以从覆盖方法更改字段周期的值? Like for example: 例如:

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);
    }
  }
}

When I try to run this code super.getClass().getDeclaredField("period") throws java.lang.NoSuchFieldException: period 当我尝试运行此代码时, super.getClass().getDeclaredField("period")抛出java.lang.NoSuchFieldException: period

You need getClass().getSuperclass() to get the superclass, not super.getClass() . 你需要getClass().getSuperclass()来获取超类,而不是super.getClass()

However, I really don't recommend doing this. 但是,我真的不建议这样做。 You're basically destroying the encapsulation of the abstract class. 你基本上是在破坏抽象类的封装。 If the abstract class isn't providing enough flexibility for its descendants, it should be fixed - going around it is just asking for trouble. 如果抽象类没有为其后代提供足够的灵活性,那么它应该是固定的 - 绕过它只是在寻找麻烦。 What if some other member of the abstract class needs to be changed whenever this one does? 如果抽象类的其他成员需要在这个时候更改,该怎么办? The whole point of having private state is so that the class is able to guard its own data. 拥有私有状态的全部意义在于,班级能够保护自己的数据。 Using reflection like this is a really ugly hack which should be an absolute last resort. 使用像这样的反射是一个非常丑陋的黑客应该是绝对的最后手段。

I'm with Jon Skeet. 我和Jon Skeet在一起。 It's easier in the long run to change the superclass's source code to either make this field protected or to delegate mutation to an overridable method. 从长远来看,更容易将超类的源代码更改为使该字段受保护或将变异委托给可覆盖的方法。 Using reflection to change the value works ok now, but it doesn't scale very well as far as maintenance over time goes. 使用反射来改变值现在可以正常工作,但是随着时间的推移,它不能很好地扩展。

ConcreteSome is not extending the abstract class AbstractAny. ConcreteSome没有扩展抽象类AbstractAny。
Try this 尝试这个

public class ConcreteSome {
    @Override
    public void doSomething() {
        Class<?> clazz = getClass().getSuperclass();
        System.out.println(clazz);
        Field p = clazz.getDeclaredField("period");
        ...

should return java.lang.Object 应该返回java.lang.Object

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM