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?
Yes, the B
class inherits the foo
method. But the variable x
in B
hides the x
in A
; it doesn't replace it.
This is an issue of scope. The foo
method in A
sees only the variables that are in scope. The only variable in scope is the instance variable x
in A
.
The foo
method is inherited, but not overridden, in B
. If you were to explicitly override foo
with the same exact code:
class B extends A
{
int x = 6;
@Override
void foo()
{
System.out.println(this.x);
}
}
Then the variable that would be in scope when referred to by this.x
would be B
's x
, and 6
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
's x
in the B
class, you can use super.x
.
Well, this is because of static binding.
1) Static binding in Java occurs during Compile time while Dynamic
binding occurs during Runtime.
2) private methods, final methods and static methods and variables
uses static binding and bonded by compiler while virtual methods are
bonded during runtime based upon runtime object.
3) Static binding uses Type(Class in Java) information for binding
while Dynamic binding uses Object to resolve binding.
4) Overloaded methods are bonded using static binding while overridden
methods are bonded using dynamic binding at runtime.
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 the x
defined in the current class : A
.
Whereas the result : 5
.
To be more precise : the foo()
method is inherited by the B
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 : the this.x
expression that refers the A.x
field in the foo()
method goes on referencing A.x
.
It is exactly the same thing as for the two previous statements :
B b = new B();
System.out.println(b.x); // refers B.x -> 6
System.out.println(((A)b).x); // refers A.x -> 5
b.foo(); // refers under the hood A.x -> 5
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 :
class A
{
private int x = 5;
int getX(){
return x;
}
void foo()
{
System.out.println(this.getX());
}
}
class B extends A
{
private int x = 6;
int getX(){
return x;
}
}
In JAVA, methods can be overridden while variables can't. So, as your method foo
is not overridden in B
, it takes the member variable from A
.
When you call
b.foo();
It checks to see if B
has overridden the method foo()
, which it has not. It then looks one level up, to the superclass A
and invokes that method.
You have then invoked A
's version of foo()
which then prints out
this.x
Now, A
can not see B
's version of x
.
In order to solve this, you have to override the method in B
class B extends A
{
int x = 6;
@Override
void foo()
{
System.out.println(this.x);
}
}
Now, calling
b.foo();
will call B
's version of foo()
and you will get the expected result.