aspose file tools*
The moose likes Programmer Certification (SCJP/OCPJP) and the fly likes Hiding of instance variables. Hard question? Big Moose Saloon
  Search | Java FAQ | Recent Topics | Flagged Topics | Hot Topics | Zero Replies
Register / Login
JavaRanch » Java Forums » Certification » Programmer Certification (SCJP/OCPJP)
Bookmark "Hiding of instance variables. Hard question?" Watch "Hiding of instance variables. Hard question?" New topic
Author

Hiding of instance variables. Hard question?

Maxwell Canprich
Greenhorn

Joined: Dec 20, 2003
Posts: 14
Hi Everybody...
I was taking mock exam JavaRanch Rules (new Beta version) and I noticed the following interesting question (question #159). I have taken the license to rewrite it here:
What is the output of:??
class Exam {
protected String difficultyLevel = "easy";
public void printDifficultyLevel() {
System.out.println( difficultyLevel );
}
}
class SCJPExam extends Exam {
private String difficultyLevel = "killing";
}
class TestExam {
public static void main(String[] args) {
SCJPExam myExam = new SCJPExam();
myExam.printDifficultyLevel();
}
}
According to JLS Section 8.3:
...
"If the class declares a field with a certain name, then the declaration of that field is said to hide any and all accessible declarations of fields with the same name in superclasses, and superinterfaces of the class."
...
And then later on:
...
"A class inherits from its direct superclass and direct superinterfaces all the non-private fields of the superclass and superinterfaces that are both accessible to code in the class and not hidden by a declaration in the class."
...
Well according to this I would have expected the String "killing"
to be displayed rather than "easy". But to my surprise "easy"
is displayed...!?!? Why?
Unfortunately I was not totally convinced by the explanation given in the mock exam: "Methods can be overridden. Attributes Cannot" Yes I know that. But attributes can indeed be hidden in subclasses!!!
According to Kathy Sierra and Bert Bates in their SCJP Study Guide page
70, paragraph 1:
"...Remember, if a subclass inherits a member, it’s
exactly as if the subclass actually declared the member itself. In other words, if a subclass inherits a member, the subclass has the member."
Then according to this, the aforementioned code could be equivalent to this one:
class Exam {
protected String difficultyLevel = "easy";
}
class SCJPExam extends Exam {
private String difficultyLevel = "killing";
public void printDifficultyLevel() {
System.out.println( difficultyLevel );
}
}
class TestExam {
public static void main(String[] args) {
SCJPExam myExam = new SCJPExam();
myExam.printDifficultyLevel();
}
}
And now you get "killing" instead of "easy"...!?! Why different now? By the way this was the behavior I was expecting always.
Could anybody please explain me or point to anything in JLS that could
bring light to this issue?
Thanks a lot in advance...
David Hadiprijanto
Ranch Hand

Joined: Sep 14, 2003
Posts: 52
Hello Maxwell,
the printDifficultyLevel() is defined in class Exam only and not overridden by SCJPExam. So, when printDifficultyLevel() is executed, it is executing within the context of class Exam, and it will look for the difficultyLevel declared in class Exam - it could not possibly know about the difficultyLevel declared in its subclass, in this case SCJPExam.
Below is a sample code that hopefully can help to clarify.
Maxwell Canprich
Greenhorn

Joined: Dec 20, 2003
Posts: 14
Thank you very much David.
Do you know where I can find information about this in JLS describing this behavior? I spent some time looking and found none.
Thanks a lot again to anyone that takes the time to help.
Max
Marlene Miller
Ranch Hand

Joined: Mar 05, 2003
Posts: 1391
(JLS? Did I hear someone say JLS? )
Hi Maxwell.
System.out.println( difficultyLevel );
In this statement, the name difficultyLevel is an expression name. So we go to JLS 6.5.6.1
If the Identifier appears within the scope (�6.3) of a visible local variable declaration (�14.4) or visible parameter declaration (�8.4.1, �8.8.1, �14.19) with that name

No it doesn�t. Keep reading.
If the Identifier appears within the scope (�6.3) of a visible field declaration with that name

Yes it does. The name difficultyLevel occurring in class Exam appears within the scope of the field declaration protected String difficultyLevel = "easy"; also occurring in class Exam. The compiler does not look at subclasses of Exam.
Otherwise, the expression name denotes a variable, the single member field with that name.

[ January 21, 2004: Message edited by: Marlene Miller ]
Marlene Miller
Ranch Hand

Joined: Mar 05, 2003
Posts: 1391

[ January 21, 2004: Message edited by: Marlene Miller ]
David Hadiprijanto
Ranch Hand

Joined: Sep 14, 2003
Posts: 52
Maxwell,
The JLS you quoted above :

"A class inherits from its direct superclass and direct superinterfaces all the non-private fields of the superclass and superinterfaces that are both accessible to code in the class and not hidden by a declaration in the class."

It talks about inheritance, not polymorphism. Same thing with the quote from K&B, it talks about inheritance.
JLS does not describe override behavior for fields, only for methods. Thus, you get polymorphism with methods (because method can be overridden), but you don't get polymorphism with fields, only inheritance.
Inheritance means a sub-class have access to its superclass feature.
Polymorphism is the ability to determine during runtime specific behavior based on the actual instance.
However, looking back at the beginning of the thread, you were expecting polymorphism, not inheritance. I.E : You have an instance SJCPExam, executing a code that attempt to access difficultyLevel that are defined both in Exam and SCJPExam, and you expect to get the difficultyLevel defined in SCJPExam.

Well according to this I would have expected the String "killing"
to be displayed rather than "easy". But to my surprise "easy"
is displayed...!?!? Why?

This is a polymorphism, not inheritance.
Hope this helps to clarify.
[ January 21, 2004: Message edited by: David Hadiprijanto ]
David Hadiprijanto
Ranch Hand

Joined: Sep 14, 2003
Posts: 52
Hello Maxwell,
another sample code for my point above...
Maxwell Canprich
Greenhorn

Joined: Dec 20, 2003
Posts: 14
Thank you very much Marlene for pointing out the
sections in JLS where I could see that this name
(a field name) is resolved at compile time. Very
useful interpretation. Thanks!
Also my biggest thanks and appreciation to David
for making things much clearer through his explanation
and good examples.
I was thinking and analyzing this whole situation quite
a while, and these are basically my conclusions
based on what I have understood of these explanations and what I have read from JLS.
Please let me know if again I am completely lost or at last I found the path.
"One can only think of polymorphism thanks to overriding.
That's why you can't think polymorphically when dealing
with instance fields or static members, because they cannot be overridden.
And if they cannot be overridden, you could then have in any object
from a class (which extends a class with a member of the same name that cannot be overridden) two definitions (different and independent) of the member, one that is visible and the other hidden (not inherited, only implemented). When hiding members with the same name, we always have a visible and a hidden members (two members) different but with the same name. When overriding we basically transform the inherited member into something new for that class definition (like "deleting" what we inherited by modifying it), such that any object of that class could only directly have one (not two) member with that name (not two objects with the same name, one visible and the other hidden-- the hidden coming from the superclass--). And because of this we could refer to any subclass object using a superclass reference variable, and get the correct and unique behaviour for that object. Not the same case when we are just hiding. Because using a superclass reference variable to refer to a subclass object that hid a member, you would get the superclass' behaviour, not the subclass' behaviour, in this case you would only be uncovering the hidden member that the object has, not the visible member which is the one the class of the object redefined."
For example I was thinking of the following:

Since we couldn't override (only redefine) compensation() on
classes Engineer and MarketingExecutive. The compiler knew
that it could resolve the compensation() call on Employee fully
at compile time, instead of just generating code that would allow to call
compensation() at runtime based on the object's real-type.
The employees[] array who had two instances of different subclasses didn't behave polymorphically.
Other would have been the story if all compensation() methods
were not static, only instance (overridable) instance methods.
Whew!!! I hope I am not asking too much... This has started to look
like a riddle... ;-)
Please let me know if I am right with my findings...
And again Thank you very so much for all your excellent help.
Max
Maxwell Canprich
Greenhorn

Joined: Dec 20, 2003
Posts: 14
Hello everybody
Please take a look at my last message and let me know if I am right
or wrong with my conclusions.
Am I right or wrong with what I said in my last message?
Thanx a lot to all of you...
Max
Marlene Miller
Ranch Hand

Joined: Mar 05, 2003
Posts: 1391
Hi Maxwell, I have read all that you have said. As I understand the language, everything you have said is correct and very nicely explained.
Definitely, all the instance fields of all superclasses, hidden or not, exist in the object of a subclass - JLS 12.5, 2nd paragraph. Instance methods of the direct superclass are accessible only using super - JLS 8.4.6.1, 2nd to last paragraph.
Now, just to reinforce your understanding, why don't you work through the questions on Inheritance (section 6) in Dan Chisholm's Topic exams.
http://www.danchisholm.net/dec20/topic/index.html
[ January 22, 2004: Message edited by: Marlene Miller ]
Marlene Miller
Ranch Hand

Joined: Mar 05, 2003
Posts: 1391
Maxwell, here is an example to reinforce the idea that the overridden methods are no longer accessible, but hidden fields are accessible.

We can access the instance methods of the direct superclass using the qualifier super, but not casting "this". We can never access the instance methods of a superclass of the direct superclass.
[ January 22, 2004: Message edited by: Marlene Miller ]
David Hadiprijanto
Ranch Hand

Joined: Sep 14, 2003
Posts: 52
Hello Maxwell,
I agree with Marlene. I think you have the right understanding.
And just to keep you on your toe...

When overriding we basically transform the inherited member into something new for that class definition (like "deleting" what we inherited by modifying it), such that any object of that class could only directly have one (not two) member with that name (not two objects with the same name, one visible and the other hidden-- the hidden coming from the superclass--).

I would not call it "deleting", and the object of that class still has two members of the same name, because you still have access to the direct superclass (only) method or member inside the class by invoking the keyword super like Marlene has pointed out.
I think if you understand what Marlene was saying above plus your current understanding, I think you will do OK. Good practice questions will definitely tell you that, definitely try the Dan Chisholms' exam.
Good luck.
Maxwell Canprich
Greenhorn

Joined: Dec 20, 2003
Posts: 14
Marlene and David you both have been of great help.
Thank you so much for explaining everything and making
things a whole lot easier to grab.
Thank you!
 
I agree. Here's the link: http://aspose.com/file-tools
 
subject: Hiding of instance variables. Hard question?