Consider below code
class A
{
int x = 5;
void foo()
{
System.out.println(this.x);
}
}
class B extends A
{
int x = 6;
// some extra stuff
}
class C
{
public static void main(String args[])
{
B b = new B();
System.out.println(b.x);
System.out.println(((A)b).x);
b.foo();
}
}
Output of the program is
6
5
5
I understand the first two but can't get my head around the last one. How does b.foo() print 5. B class will inherit the foo method. But shouldn't it print what b.x would print? What exactly is happening here?
Well, this is because of static binding.
In JAVA, methods can be overridden while variables can't. So, as your method
foo
is not overridden inB
, it takes the member variable fromA
.Yes, the
B
class inherits thefoo
method. But the variablex
inB
hides thex
inA
; it doesn't replace it.This is an issue of scope. The
foo
method inA
sees only the variables that are in scope. The only variable in scope is the instance variablex
inA
.The
foo
method is inherited, but not overridden, inB
. If you were to explicitly overridefoo
with the same exact code:Then the variable that would be in scope when referred to by
this.x
would beB
'sx
, and6
would be printed. While the text of the method is the same, the reference is different because of scope.Incidentally, if you really wanted to refer to
A
'sx
in theB
class, you can usesuper.x
.Fields are not overridable in Java and subclasses with same field names as the parent class shadow "only" the fields of the parent class.
So
this.x
refers to thex
defined in the current class :A
.Whereas the result :
5
.To be more precise : the
foo()
method is inherited by theB
subclass but it doesn't mean that the behavior of the inherited method will change about instance fields referenced since as said fields are not overridable : thethis.x
expression that refers theA.x
field in thefoo()
method goes on referencingA.x
.It is exactly the same thing as for the two previous statements :
The very good answer of rgettman shows how you can overcome the field hiding in the subclass.
A alternative to overcome the hiding relies on making the instance field
private
(which is recommended) and providing a method that returns the value.In this way you benefit from the overriding mechanism and the field hiding is not an issue any longer for clients of the classes :
When you call
It checks to see if
B
has overridden the methodfoo()
, which it has not. It then looks one level up, to the superclassA
and invokes that method.You have then invoked
A
's version offoo()
which then prints outNow,
A
can not seeB
's version ofx
.In order to solve this, you have to override the method in
B
Now, calling
will call
B
's version offoo()
and you will get the expected result.