Hiding of instance variables. Hard question?

M

maxw_cc

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...
 
M

Mike Schilling

maxw_cc said:
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?


SCJPExam.difficulty level, as you say, *hides* Exam.difficultyLevel, it
doesn't *override* it. That is, in the scope SCJPExam, difficultyLevel
means SCJPExam.difficultyLevel. That doesn't change the fact that in the
scope Exam, difficultyLevel means Exam.difficultyLevel. In the line:

System.out.println( difficultyLevel );

difficultyLevel is bound at compile-time (not run-time) to
Exam.difficultyLevel.

In other word, fields, unlike methods, are never virtual.
 
M

Marc Dzaebel

use

System.out.println( getClass().getField("difficultyLevel").get(this) )

to simulate virtual fields (which is of course quite slow and exceptions
have to be catched).

E.g.

class VirtualFieldAccess {
public static void main(String[] args) {
try { System.out.println(new A().c());
System.out.println(new B().c());
} catch (Exception e) { e.printStackTrace();}
}
}
class A {
public String c="a";
Object c() throws Exception { return getClass().getField("c").get(this);}}
class B extends A {
public String c="b";
}

will print "a" and "b" respectively.
 
M

maxw_cc

Mike Schilling said:
In other word, fields, unlike methods, are never virtual.

Thank you very much to Mike and Marc for your good and useful
answers.

Specially thanks to Mike for pointing out that fields are
fully resolved at compile time, using the field declaration at scope
in compile time.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,776
Messages
2,569,603
Members
45,189
Latest member
CryptoTaxSoftware

Latest Threads

Top