My code is:
class Foo {
public int a=3;
public void addFive() {
a+=5;
System.out.print(\"f \");
}
}
class Bar extends Foo {
public int a=8;
You cannot override variables in Java, hence you actually have two a
variables - one in Foo
and one in Bar
. On the other hand addFive()
method is polymorphic, thus it modifies Bar.a
(Bar.addFive()
is called, despite static type of f
being Foo
).
But in the end you access f.a
and this reference is resolved during compilation using known type of f
, which is Foo
. And therefore Foo.a
was never touched.
BTW non-final variables in Java should never be public.
With such a question, the SCJP exam is assessing your knowledge of what is known as hiding. The examiner deliberately complicated things to try to make you believe that the behavior of the program depends only on polymorphism, wich it doesn't.
Let's try to make things a bit clearer as we remove the addFive()
method.
class Foo {
public int a = 3;
}
class Bar extends Foo {
public int a = 8;
}
public class TestClass {
public static void main(String[]args) {
Foo f = new Bar();
System.out.println(f.a);
}
}
Now things are a bit less confusing. The main
method declares a variable of type Foo
, which is assigned an object of type Bar
at runtime. This is possible since Bar
inherits from Foo
.The program then refers to the public field a
of the variable of type Foo
.
The error here would be to believe that the same kind of concept known as overriding applies to class fields. But there is no such a concept for fields: the public field a
of class Bar
is not overriding the public field a
of class Foo
but it does what is called hiding. As the name implies, it means that in the scope of the class Bar
, a
will refer to Bar
's own field which has nothing to do with Foo
's one. (JLS 8.4.8 - Inheritance, Overriding, and Hiding)
So, when we are writing f.a
, which a
are we referring to? Recall that resolution of the field a
is done at compile time using the declaring type of the object f
, which is Foo
. As a consequence, the program prints '3'.
Now, lets add an addFive()
method in class Foo
and override it in class Bar
as in the exam question. Here polymorphism applies, therefore the call f.addFive()
is resolved using not the compile time but the runtime type of object f
, which is Bar
, and thus is printed 'b '.
But there is still something we must understand: why the field a
, which was incremented by 5 units, still sticks to the value '3'? Here hiding is playing around. Because this is the method of class Bar
which is called, and because in class Bar
, every a
refers to Bar
's public field a
, this is actually the Bar
field which is incremented.
1) Now, one subsidiary question: how could we access the Bar
's public field a
from the main
method? We can do that with something like:
System.out.println( ((Bar)f).a );
which force the compiler to resolve the field member a
of f
as Bar
's a
field.
This would print 'b 13' in our example.
2) Yet another question: how could we work around hiding in addFive()
method of class Bar
to refer not to the Bar
's a
field but to its superclass eponimous field ? Just adding the super
keyword in front of the field reference does the trick:
public void addFive() {
super.a += 5;
System.out.print("b ");
}
This would print 'b 8' in our example.
Note that the initial statement
public void addFive() {
this.a += 5;
System.out.print("b ");
}
could be refined to
public void addFive() {
a += 5;
System.out.print("b ");
}
because when the compiler is resolving the field a
, it will start to look in the closest enclosing scope from within the method addFive()
, and find the Bar
class instance, eliminating the need to use explicitely this
.
But, well, this
was probably a clue for the examinee to solve this exam question !
F
is a reference of type Foo
, and variables aren't polymorphic so f.a
refers to the variable from Foo
which is 3
How to verify it?
To test this you can remove a
variable from Foo
, it will give you compile time error
Note: Make member variable private
and use accessors to access them
Also See
Since you are doing f.a
you will get the value of a
from the class Foo
. if you had called a method to get the value, e.g getA()
then you would have gotten the value from the class Bar
.