21

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?

3
  • 2
    But foo() is not overridden in B, why should it? There's no such thing as variable overriding... Commented Jun 29, 2018 at 17:29
  • 3
    Because dynamic linking works only for methods. So you get a variable from that class which reference you have Commented Jun 29, 2018 at 17:30
  • 1
    These are two different variables. If you want to override x in B, you could write a constructor: B() { super.x = 6; } Commented Jun 29, 2018 at 17:31

5 Answers 5

17

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.

Sign up to request clarification or add additional context in comments.

2 Comments

So it looks to me that data hiding is a trap. If one wants to hide a variable, they have to override all methods that touch that variable...
They would have to override all methods that touch that variable only if they wanted to replace the superclass variable with another variable. It's confusing at best when inheritable fields are hidden.
2

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.

Comments

2

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;
    }
}

2 Comments

The getX() in B must return x
@user7 Oh thanks for that. Don't hesitate to edit the post the next time.
1

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.

Comments

0

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.

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.