11

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?

Cratylus
  • 52,998
  • 69
  • 209
  • 339
  • 2
    But the method display _is_ called in the scope of the parent class Animal, and in this scope, the name has been assigned "Animal". There is no hiding there, hiding would come around if you overrided the method display in the subclass Dog. – Alexandre Dupriez Aug 20 '12 at 21:59
  • So the actual `Dog`'s object memory layout has both variables?I though the "hiding" made only 1 available – Cratylus Aug 20 '12 at 22:01
  • I do not know what you mean by memory layout, but yes, a Dog object has basically two name attributes: this.name and super.name. – Alexandre Dupriez Aug 20 '12 at 22:02
  • The `Animal.name` field is still the only one visible from the `Animal` class itself. The `Dog.name` field is the one used by the `Dog` method implementations. – Louis Wasserman Aug 20 '12 at 22:03
  • You might want to look at [this related question](http://stackoverflow.com/questions/9414990/if-you-override-a-field-in-a-subclass-of-a-class-the-subclass-has-two-fields-wi) – Don Roby Aug 20 '12 at 22:05
  • @LouisWasserman:You mean the part of the memory layout of `Dog` that is the `Animal`?So the fact that the variable hides the parent is not visible to that area? – Cratylus Aug 20 '12 at 22:07

4 Answers4

13

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

Razvan
  • 9,925
  • 6
  • 38
  • 51
  • So when you hide the parent variable, both are kept as part of the object and visible to the corresponding scope/methods? – Cratylus Aug 20 '12 at 22:05
  • @Cratylus, there is storage for *both* fields for the object instance -- one for `Animal.name`, and one for `Dog.name`. – obataku Aug 20 '12 at 22:08
  • @veer:So the each field is visible to specific scope only? – Cratylus Aug 20 '12 at 22:09
  • @Cratylus: `Animal.name` is visible from both scopes, since it's `public`; however, since `Animal` has no clue there is a subclass named `Dog` with a `name` field, the `name` symbol is resolved as a reference to the local `Animal.name` field. In `Dog`, similarly, `name` will resolve to `Dog.name`; that being said, you can also access `Animal.name` using `super.name` :-) – obataku Aug 20 '12 at 22:11
  • @veer:`Animal has no clue there is a subclass named Dog with a name field`. But the compiler resolves this.And the current static type is actually a `Dog`.I am not sure I follow how this mechanism works – Cratylus Aug 20 '12 at 22:13
  • @Cratylus the compiler resolves the `name` symbol, yes... though I don't quite see your point. You can't override a field -- only a method. What you're doing is called *shadowing* the superclass `name` field. – obataku Aug 20 '12 at 22:16
  • @veer:I am trying to understand how this works.I am not trying to make a point – Cratylus Aug 20 '12 at 22:18
  • @Cratylus maybe you should read [§8.3 of the Java Language Specification](http://docs.oracle.com/javase/specs/jls/se7/html/jls-8.html#jls-8.3); shadowing in general is documented in [§6.4.1](http://docs.oracle.com/javase/specs/jls/se7/html/jls-6.html#jls-6.4.1). – obataku Aug 20 '12 at 22:23
  • @Cratylus: I think you should post a new question if you want a strict, technical answer to your update. If you want an intuitive answer, I can tell you that: "this" (at runtime) is resolved to the object on which the display() method is called (of the type Dog). Hence the getClass() returns Dog. At the same time the name, being a field, is resolved to the name in Animal, the scope in which the display is called. – Razvan Aug 21 '12 at 17:23
  • @Razvan:But if I post a new question,the example code would be the same.My concern is that it will be closed as a duplicate – Cratylus Aug 21 '12 at 18:35
  • @Cratylus: give it a try ! Nothing bad can happen. – Razvan Aug 21 '12 at 18:40
  • @Razvan:I think that this from JLS applies here:`The scope of a declaration of a member m declared in or inherited by a class type C (§8.1.6) is the entire body of C, including any nested type declarations.`.So the actual object is `Dog` but the `display()` method is not in the scope of `Dog.name` (or better `Dog.name` is not in the scope at this point).This is why the `Animal.name` is chosen since it is the only visible at that point. – Cratylus Aug 21 '12 at 22:01
2

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.

Louis Wasserman
  • 191,574
  • 25
  • 345
  • 413
  • But the static type in this case `d.display` is `Dog`.So the compiler knows it is a `Dog` and knows it has a `name`.The actual operation is not overriden, but I can not follow the mechanism here as to why there is a scope. `d` has been resolved to a `Dog`.The `display` is inherited but operated on a `Dog`.So I can't follow the mechanism here.Why is there a scope?Hasn't the variable been resolved by the static type? – Cratylus Aug 20 '12 at 22:17
  • Yes, `d` is known to be a `Dog`, but the implementation of `display()` is in the `Animal` class, which doesn't know anything about the `name` field in the `Dog` class -- it only knows about the `name` field in the `Animal` class. The code I've written above is _exactly_ equivalent to the code you wrote; can you see why it works that way there? – Louis Wasserman Aug 20 '12 at 22:44
  • +1, and this is a good way of looking at it. If you have a reference of type `Animal`, its fields will resolve *non-polymorphically* to a field on `Animal`. If a subtype of `Animal` has a field that happens to have the same name, it doesn't factor in at all. – yshavit Aug 20 '12 at 23:54
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 Singh
  • 662
  • 1
  • 9
  • 20
1

A simple Junit test run in debug mode shows that there are indeed two 'name' variables in the Dog object. Now, answering the question asked in the latest update of OP:

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

Dog d = new Dog
d.display();

Here, 'd' contains two variables -> one is the inherited one, other is the one defined in dog class, both having same name. Now, when display() is invoked on Dog object, since it did not override the display() method of Animal class, JVM runs the display() method of Animal class.

System.out.println("Current class is "+ this.getClass().getName());  

will print Dog because it is the actual object on which the method was invoked.

System.out.println("My name is "+ name);  

will print 'My name is Animal' , because as said before, object of Dog has both variables in it, but once inside the Animal.display() method, the value of variable Animal.name is chosen due to the scope.

Sudhanshu
  • 11
  • 1
  • 2