views:

676

answers:

3

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

+11  A: 

You need getClass().getSuperclass() to get the superclass, not 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.

Jon Skeet
A: 

ConcreteSome is not extending the abstract class 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

Carlos Heuberger
Fixed it, thank you
Boris Pavlović
+2  A: 

I'm with 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.

matt b