40

I am having some doubts about this Java code. The output it gives is "furry bray". My questions:

  1. Why do i get this output?
  2. How can I access the String object reference "name" in ZooKeeper class?
  3. If it has something to do with variable shadowing, then which variable is being shadowed?

Code:

class Mammal {
   String name = "furry ";
   String makeNoise() { return "generic noise"; }
 }
 class Zebra extends Mammal {
   String name = "stripes ";
   String makeNoise() { return "bray"; }
 }
 public class ZooKeeper {
   public static void main(String[] args) { new ZooKeeper().go(); }
   void go() {
     Mammal m = new Zebra();
     System.out.println(m.name + m.makeNoise());
     //Output comes as "furry bray". Please explain this.
     //And how can we access the name variable, the one having "stripes " in it.
     //Does it have something to do with Variable Shadowing?
   }
 }
Community
  • 1
  • 1
Prateek Singla
  • 679
  • 2
  • 10
  • 22
  • 1
    Possible duplicates: http://stackoverflow.com/questions/12589274/slight-confusion-regarding-overriding-where-variables-are-concerned; http://stackoverflow.com/questions/10722110/overriding-variables-java; http://stackoverflow.com/questions/427756/overriding-a-super-class-instance-variables – RAS Jun 05 '13 at 13:55
  • When the child and parent class both have a variable with same name child class's variable hides parent class's variable so when we try to access the variable from parent's reference by holding child's object, it will be accessed from the parent class, read more on my blog https://programmingmitra.com/2018/02/what-is-variable-shadowing-and-hiding.html – Naresh Joshi Jul 07 '20 at 09:12

5 Answers5

63

Variables aren't polymorphic. When you access m.name, that will always use the Mammal.name field which is part of that object, regardless of the execution-time type of the object. If you need to get access to Zebra.name, you need an expression with a compile-time type of Zebra.

The makeNoise method is called virtually though - the implementation used at execution time does depend on the type of the object.

Note that if you make all your fields private - which is generally a good idea anyway - this doesn't end up being an issue.

This is actually hiding rather than shadowing. See JLS section 8.3 for details on hiding, and section 6.4.1 for shadowing. I can't say that I always keep the differences straight...

Jon Skeet
  • 1,421,763
  • 867
  • 9,128
  • 9,194
  • 5
    So, in order to the correct output, you have to create a getter method like `public String getName(){return this.name;}` – LuigiEdlCarno Jun 05 '13 at 13:30
  • @LuigiEdlCarno: You'd need to override it in `Zebra` though, with the same implementation (which would refer to a different field). – Jon Skeet Jun 05 '13 at 13:32
  • 1
    Yes, that's what I ment. You need to create that getter in Zebra, too. – LuigiEdlCarno Jun 05 '13 at 13:33
  • 1
    @JonSkeet - Thanks... I never knew.. there was a thing known as hiding of variables. :) – Prateek Singla Jun 05 '13 at 13:37
  • 1
    @LuigiEdlCarno Instead of overriding getters would not it be better to create protected field `name` and public getter for `name` in base class and assign `name` in constructors of derived classes? I find this more logical and saves few key-strikes. – Leri Jun 05 '13 at 13:41
  • 2
    @PLB: Well I'd make it a *private* field in the superclass - but it depends on what's required. We don't really have a genuine use case here, with explanations of what the two separate fields are meant to mean. – Jon Skeet Jun 05 '13 at 13:42
  • If you really want to, you may modify your name variable by calling super.name in the zebra's constructor, but this would not make much sense... – lrl Jun 05 '13 at 13:48
  • 1
    @Omar: I reached the rep cap significantly before answering this question :) – Jon Skeet Jun 05 '13 at 16:16
16

Output comes as "furry bray". Please explain this.

fields in java programs are not accessed via dynamic lookup. Instead they are resolved statically while compile time. That's why you are getting furry for m.name. Whereas, methods in java programs are accessed via dynamic lookup. That's why you are getting bray for m.makeNoise().

And how can we access the name variable, the one having "stripes " in it?

And if you want to access Zebra.name , you should type cast m to 'Zebra'.This would look like this:

System.out.println(((Zebra)m).name + m.makeNoise());

UPDATE
The phenomena that is exhibiting here is the result of Fields Hiding rather than variable shadowing.

Vishal K
  • 12,976
  • 2
  • 27
  • 38
9

There is no variable overriding in Java, you declared name in both the parent and the child but you referred to it through a parent reference variable. That's why you got 'furry'.

There is overriding for methods, which is why you got bray. Because on runtime it looked at the real object in the heap and saw it's a Zebra.

4

Variable names in Java are resolved by the reference type, not the object they are referencing. So, m.name refers to the variable name in Mammal even dough m is a Zebra.

Stijn Geukens
  • 15,454
  • 8
  • 66
  • 101
3

It happened because your field name from Mammal is just hidden by name field from Zebra. You can then access it simply by casting to required type.
On the other side makeNoise() method overrides same method from parent so you can't access implementation from parent anymore.

Ondrej Bozek
  • 10,987
  • 7
  • 54
  • 70