Polymorphism on member variables. I know it is not possible, I don't understand this specific case

I know the behavior, but I am not 100% sure on why this occurs.
I understand that there is no polymorphism for instance variables in java. The variables are resolved statically by the compiler.
But in the following I am confused on something:

class Animal{  
   String name = "Animal";  
   public void display(){  
    System.out.println("My name is "+ name);  
   }  
}  

public class Dog extends Animal {   
   String name = "Dog";   

   public static void main(String[] args) {  
        Animal a = new Dog();  
        Dog d = new Dog();  
        System.out.println(a.name);//Line 1  
        a.display();//Line 2   
        d.display();//Line 3  
   }  
}  

I undertand that in Line 1 it will display Animal as it is the static type of a (resolved by compiler).
What confuses me is why Line 3 will also display My name is Animal?
The method will be tried to be called on Dog since this is the actual object at runtime and since it is not overidden the method will be found in the parent class Animal.
What I don't get is why the name of the parent class is used inside the method display if the actual object operated on is a Dog. Doesn't it hide the parent's name variable? It does not seem to me like it is statically resolved since the type is Dog. Isn't it part of the oject's memory layout?
It is like inside display only the parent's variable is visible. Why?

Update:

The answers by @Razvan and @LouisWasserman have been helpful.
I have 1 last question after these:
The point from both seems to be the following:
From @Razyan
System.out.println("My name is "+ this.name); //<-- note the this
From @Louis
That the this refers to Animal and that the implementation of display() is in the Animal class.

So far ok. But how are these points consistent with the fact that if I modify display() as follows:

class Animal{  
   String name = "Animal";  
   public void display(){  
    System.out.println("Current class is "+ this.getClass().getName());  
    System.out.println("My name is "+ name);  
   }  
}  

Then the result of:

 Dog d = new Dog();  
 d.display();  

Current class is Dog
My name is animal

I was expecting that this inside the display would be Animal as I understood the answers here. But it is not. Why?

3 Answers
  1. When you invoke d.display() the Animal.display() is called, since you don't override it in the Dog class.

    So an imaginary implementation of Dog.display() would be something like:

     public void display(){  
        super.display();
     }
    

    And the implementation of Animal.display() is:

     public void display(){  
        System.out.println("My name is "+ this.name); //<-- note the this
     } 
    

    The Animal.display() method is not even aware of the existence of an object Dog and consequently of its name variable

    2012-08-20 22:07:21
  2. Here I am summarizing all other's points in one answer so that one can get a clear picture of it without putting much effort.

    Conceptually code can be thought of as

    class Animal{  
       String name = "Animal";  
       public void display(){  
        System.out.println("My name is "+ this.name);  
       }  
    }  
    
    public class Dog extends Animal {   
       String name = "Dog";  
       public void display(){  
        super.display();
     } 
    
       public static void main(String[] args) {  
            Animal a = new Dog();  
            Dog d = new Dog();  
            System.out.println(a.name);//Line 1  
            a.display();//Line 2   
            d.display();//Line 3  
       }  
    } 
    

    Here in the Dog's class we're shadowing name field of Animal class ie. Dog's instance will have two instance variable named name one is Animal.name (from inheritance which holds value "Animal") second is Dog.name(which holds value "Dog"). Dog.name hides Animal.name in Dog class.
    At Line-3 display() method is invoked on the instance of Dog.Dog doesn't override display() method of Animal so ultimately Animal.display() method gets invoked. In this method this refers to Dog and as Dog has two namein it, one which is in the scope of Animal gets printed.(because being a superclass Animal is unaware of Dog class and Dog.name)

    Deepankar Singh2012-08-20 22:01:54
  3. This might be a more useful way of thinking about it: the fact that the variables have the same name doesn't matter in the slightest. This code will behave exactly the same as

    class Animal{  
       String foo = "Animal";  
       public void display(){  
        System.out.println("My name is "+ foo);  
       }  
    }  
    
    public class Dog extends Animal {   
       String bar = "Dog";   
    
       public static void main(String[] args) {  
            Animal a = new Dog();  
            Dog d = new Dog();  
            System.out.println(a.foo);//Line 1  
            a.display();//Line 2   
            d.display();//Line 3  
       }
    }
    

    The point is, the field name in the Dog class is treated as completely, utterly separate from the field name in Animal, in terms of which is seen by which methods. When you refer to a.name directly, it only knows that a is an Animal, so it uses the name field from the Animal class.

    2015-09-17 21:55:10
Related Articles
You Might Also Like