nick woodward wrote:for example: say a class A, is extended by B. B overrides A's only method (print), which prints a '2' (where as A's prints a '1').
when B is created, it implicitly calls super, calling A's constructor, which is designed to call the print method (polymorphically calling B's version). This prints '0' because B's constructor has not run/initialized the variable, correct?
nick woodward wrote:so when is the variable created? when the class is loaded? i would've previously assumed that the constructor 'creates' the members of the object, so any methods or ivars called prior to the constructor would cause an exception.
At the moment an object is created, all instance variables exist and are initialized with their default values. But iB will get its actual value (2) when the constructor of A has finished and the constructor of B is being executed.
Experience keeps a dear School, but Fools will learn in no other.
---
Benjamin Franklin - Postal official and Weather observer
nick woodward wrote:is the call to the constructor (eg new B()) when the object is created then? and the constructor just deals with the initialization? to answer my own question, i don't think it can be, because why then does your second example cause an exception? it would surely just pass a default value!
JLS, section 8.8.7.1. Explicit Constructor Invocations wrote:An explicit constructor invocation statement in a constructor body may not refer to any instance variables or instance methods or inner classes declared in this class or any superclass, or use this or super in any expression; otherwise, a compile-time error occurs.
nick woodward wrote:...wheres the confused smiley......!
Roel De Nijs wrote:So just remember it's not only instance variables, but also instance methods which will cause a compiler error if you use them in an explicit constructor invocation statement. It doesn't matter if you try to invoke a super or this constructor.
nick woodward wrote:I'll write it out as I now understand it, for the sake of my own clarity as much as anyone elses understanding of it:
nick woodward wrote:What I still am failing to grasp is where the change occurs in the object variables. On the way up the hierarchy the members of the current object seem to not exist at all (point 2). On the way back down they return default values prior to the _init() method running (point 3).
nick woodward wrote:i think my problem probably lies with what Mike has said - the design decision to not allow access to member variables on the way up the hierarchy, even though (as far as I can tell / comprehend) there doesn't seem to be much of a reason for this. i think it will probably become more clear when i have more experience!
Roel De Nijs wrote:
Maybe that design decision is made to prevent object creation mayhem like thisWhat will be the value of iA when you create a B instance? It could be 0 or 6: 0 is not what you would expect and 6 requires to create/initialize the subclass before its parent classes (and that's like building a house and starting with the attic
)
Mike. J. Thompson wrote:With the case of accessing instance fields in the call to super, are you happy that that will always result in accessing an uninitialised variable and so will always be wrong?
Mike. J. Thompson wrote:
In the case of calling overridden methods from the constructor, consider the following class:
So, should the compiler allow that to compile? Would allowing that class to compile result in access of an uninitialised variable?
It is impossible for the compiler to answer that question. It will not be possible to know until runtime whether the code above will print out "What should the compiler do here?", or do something else entirely.
You might think that the compiler should just look at all the other classes, and see if any other class has overriden that method, but that would not work. What happens if the class that overrides that method has not been written yet? In that case the compiler that is compiling MyClass could not possibly know if that code would result in accessing an uninitialised variable yet.
So the possibly-polymorphic method call differs from the call to super. Where the call to super() will always result in uninitialised variable access, the method call from the constructor only has the possibility to result in uninitialised variable access. The designers of Java could have just disallowed constructor calls from calling any method that is not private or static if the class is not final, but that would have meant a lot of perfectly safe code would not compile.
Trying to collect the broken pieces of my life,in the process of making out a beautiful picture out of it.
Sachin Tripathi wrote:But it still prints :0(Why?)
Sachin Tripathi wrote:Well Roel you said that:
At moment object is created all instance variable existsand initialized with their default values. That I find somehow misleading
Consider a case
Where class C extends B
And we create object of C in its main method
Now when constructor of C is invoked
It implicitly calls constructor of B(but don't create its (B)object) (and also marked its(B) field as private)
Now it implicitly invokes constructor of A having print()
Which will run B's version
But B's instance field shouldn't exist as its object is not created
But it still prints :0(Why?)
Don't you think I too deserve a cow now?![]()
Trying to collect the broken pieces of my life,in the process of making out a beautiful picture out of it.
nick woodward wrote:It just seems odd to have a compiler error there, but not with the polymorphic call - which is why I asked where exactly the variables were declared rather than initialized - but i understand now that its a design thing, just not quite why!
Roel De Nijs wrote:
nick woodward wrote:It just seems odd to have a compiler error there, but not with the polymorphic call - which is why I asked where exactly the variables were declared rather than initialized - but i understand now that its a design thing, just not quite why!
It's not odd at all!
The compiler simply has different information. When you use this codethe compiler definitely knows that iB is used in the super() call, because that's the actual code so a quick glance of the compiler at the code is enough to know this.
...
PS. Do you know why you got the NullPointerException at runtime?
nick woodward wrote:*fake edit: ahh! calling .toUpperCase() on null?
Mike. J. Thompson wrote:And that is why it is best practice that a constructor never calls any method in its class that could possibly ever be overridden in a subclass.
nick woodward wrote:i almost forgot statics in all of this..... they, and static blocks, must run before all of this then, right? before the first constructor call to super or this? which is why they can be used in either call?
Did you see how Paul cut 87% off of his electric heat bill with 82 watts of micro heaters? |