This week's book giveaway is in the OO, Patterns, UML and Refactoring forum. We're giving away four copies of Refactoring for Software Design Smells: Managing Technical Debt and have Girish Suryanarayana, Ganesh Samarthyam & Tushar Sharma on-line! See this thread for details.
In the SCJP Study Guide it says: "You cannot make a call to an instance method, or access an instance variable, until after the super constructor runs." (Earlier, it mentions that a call to super() is inserted by the compiler.)
But isn't that just a logistical issue? By definition instance variables need an instance of the class to be accessed. How else would I access them unless the constructor has run (which means I made an instance)?
I think the point is that all constructors higher in the hierarchy must complete before you can access instance members. The implicit super() (or explicit super() if you put it in there yourself), must be the first line in the constructor, otherwise it will not compile.
Pay good attention to constructor chaining in your SCJP prep.
Joined: Jan 24, 2010
Thank you Keith.
Doesn't the implicit super() or explicit super() run only if an instance is created usng "new"? If so, how would I possibly access any instance members without creating an instance using new? ClasssName.member only works for non-instance menbers.
It's as if the book is warning me against attempting to do something that's impossible to do anyway. I mean, once the constructor chaining begins, I can't interrupt it.
Russ Russell wrote:By definition instance variables need an instance of the class to be accessed. How else would I access them unless the constructor has run (which means I made an instance)?
Despite their name, constructors do not create an instance of a class - they only initialise it. At the time the constructor is called the class instance and all it's member variables already exist. The need to make a call to super() before doing anything else in the constructor is to make sure all the members of the parent class(es) are correctly initialised first.
Russ Russell wrote:In the SCJP Study Guide it says: "You cannot make a call to an instance method, or access an instance variable, until after the super constructor runs."
I interpreting that to mean you can't access instance members from within the constructor until the supers complete their run.
It's as if the book is warning me against attempting to do something that's impossible to do anyway.
If there's a way to do it, I can't think of it.
It isn't impossible. The way to do it is to have the constructor of the super-class of your class call an instance method which is overridden by your class. Things can get confusing real fast if you do this.
As you'll see, the first time Sub.doSomething() is called, i and s will not have been initialized yet, and their values will be 0 and null respectively. Only after the implicit (or explicit) call to super() has ended will i and s get their values.
That's why methods shouldn't be called from any constructor unless
a) they are private, and therefore cannot be overridden
b) they are final, and therefore cannot be overridden
There is a questionable option c) that would allow it if it's properly documented that it can / will be called from a constructor, and therefore overriding methods should not use any fields (directly or indirectly through other method calls), but I think the majority of people will say it's not a valid option.
Thank you Rob Spoor. I can't quite understand how it works yet, but yes, you have code running before the constructor ran. Is it because when the Super constructor calls doSomething(), it is calling Sub's doSomething()?
It's hard for me to understand why Super calling doSomething() would invoke Sub's version of doSomething() instead of its own version. Can you tell me? I mean, Sub inherits Super. Not the other way around.
Is Super inheriting Sub's doSomething()? How can Super be a Sub when class Sub extends Super?
The closest thing I've seen to this was in the Polymorphism chapter when you have something like Super s = new Sub();
When you create a new Sub, it goes through these steps:
1) call super() - in other words, the Super constructor.
1a) call getClass() which returns the class of the new Sub object.
1b) call doSomething() which is the overridden method of the new Sub object.
2) initialize i and s.
3) print out i and s.