I have wired experience with reflections. At first some sample code:
public abstract class A {
public A () {
init();
}
public abstract void init ();
}
public class B extends A {
private int i = 0;
public B () {
super();
System.out.println(i);
}
public void init () {
i = 1;
}
}
Somewhere in my code I use the reflection api to instantiate an object B.
Class<AbstractSection> bc = (Class<AbstractSection>) Class.forName(B);
Constructor<?> bcon = bc.getConstructor();
B b = (B) bcon.newInstance();
What I expected was an instance of B with the variable i set to value ‘1’. What I got is an instance of B with i still set to ‘0’.
With a closer look with a debugger I saw that this is not exactly correct: i is NOT still set to ‘0’. It is changed to ‘1’ in
the init() method and set back to ‘0’ in the very moment when the super() call returns.
Anyone a clue? Thanks in advance,
manuel
PS: I know I can solve this by calling init() not in the super class but in the inheriting constructor.
For starters, this is nothing to do with reflection – you’d get the same results if you instantiate the class yourself.
Your confusion likely stems from the way that the
ifield is defined – it looks like it’s set to0as soon as it “exists”. In reality, the assignment to zero is one of the first lines of your constructor (though, crucially, after the call tosuper()as is required by constructors in general).In other words, your class is exactly equivalent to the following:
I presume you can see now why the output is
0instead of1– because the call toinit()happens before the field is initialised to0.It is for this, and other reasons, that on the whole you should avoid calling subclass methods from a superclass constructor – since the subclass won’t even have been initialised at this point, so invariants could easily be violated. (Calling methods on an unconstructed object is always a very bad idea!) That’s the root cause of your problem, and the direction that you should be looking to address with a fix.
Constructors should constrain themselves to only calling methods that are private or final, for this reason. For more details, see (amongst others):