1

I thought I understood the concept of shadowing. But this Code made me wonder:

public class Counter {
int count = 0;

public void inc() {
    count++;
}

public int getCount() {
    return count;
}

}

class StepCounter extends Counter {
int count = 0;
int step = 1;

public StepCounter(int step) {
    this.step = step;
}

public void inc() {
    count += step;
}

}

StepCounter sc = new StepCounter(2);
    sc.inc();
    sc.inc();
    System.out.println(sc.getCount());
    System.out.println(sc.count);

So basically the Static Type of sc is StepCounter. It's counter is incremented twice, so it's at 4 after the first two commands. My count Variable is not a private one, it is package private (since I haven't declared any visibility on it). So if I call the .getCount() method on sc, it first looks for it in StepCounter. There is none, so it goes to Counter. Here it finds the getCount() method. that method returns count. If count had been static or private, I'd understand why it returns 0. But why does it return 0 in this case? Even if I made the variable count public in StepCounter, the result would still be 0.

Roman C
  • 49,761
  • 33
  • 66
  • 176
InDaPond
  • 574
  • 3
  • 6
  • 23
  • 5
    Because member variables are not polymorphic. Counter.getCount always returns Counter.count. – Oliver Charlesworth Jan 31 '16 at 13:49
  • Related: http://stackoverflow.com/questions/32422923/why-does-java-bind-variables-at-compile-time – M A Jan 31 '16 at 13:51
  • Also the field here is not shadowed. It's hidden. – M A Jan 31 '16 at 14:00
  • I'm still having a hard time, in the "related" answer it is easy too see b/c the methods are static. In mine, they are not. Are you saying that member variables (variables created inside the scope of a class) are always static? – InDaPond Jan 31 '16 at 14:01

3 Answers3

2

getCount() can only access the field counter tht was defined in the parent class. This class is resolved at compile time of the parent class. There is no copy of the method getCounter() in the child.

In the child class, you can use

Counter.this.count

to access the parent counter. But to avoid bad surprises, you should never name a field in such a ambiguous way.

Has QUIT--Anony-Mousse
  • 76,138
  • 12
  • 138
  • 194
1

In Java, fields can't be overridden. Only methods can be overriden. So having a 'count' variable in StepCounter doesn't override the 'count' field in the super class 'Counter'. It just creates another field. However 'getCount' method returns the value of the 'count' field in the superclass. To have the desired functionality need to override the 'getCount' method in the StepCounter class.

Dev Blanked
  • 8,555
  • 3
  • 26
  • 32
  • My Object has the dynamic type Counter. Now the getCount() method says "return your field called count". Shouldn't it look in its own scope (B) first? – InDaPond Jan 31 '16 at 14:04
  • @InDaPond fields can never be overridden so when getCount method is executed it sees 'count' field defined in super class only – Dev Blanked Feb 01 '16 at 06:45
1

You should always avoid shadowing as much as possible, it could introduce serious unpredictable behaviours for your code. What you're missing here is the concept of variable scoping in Java. count is merely a shorthand for this.count. So, given your code what the resolver does here, after the invocation of the getCounter() method, is:

  1. Try to resolve getCounter() as an instance of StepCounter class
  2. Fails, try to find any class ancestors
  3. Nearest ancestor is Counter, so the context is switched over Counter class
  4. Try to resolve getCounter() in Counter class
  5. Method found, try to resolve the value of count
  6. getCounter() is non-static, so count is actually this.count (if getCounter() were to be static it would be Counter.count)
  7. this.count resolves to value 0 in the scope of the instance of Counter class
  8. 0 is returned
  • this outside the scope of a constructor refers to the current object, right? So this.getClass() is StepCounter, so I still have problems figuering out step 7.. – InDaPond Jan 31 '16 at 14:09
  • `getClass()` gives you the reference for the class on which your instance was constructed. In your example you have two separate values for `count` property in the `sc` instance you created. One in the context of `StepCounter` class and one in the context of `Counter` class. You can try that yourself just by adding this line at the end of your code: `System.out.println(((Counter) sc).count);`. `this` in the scope of `getCounter()` method takes the value of `(Counter) this`. – Fergus Rataporn Jan 31 '16 at 14:22
  • Thanks a lot! So whenever I write this as an objecte reference, it is equal to writing (Cast of class I am writing this in) this. Is this correct? – InDaPond Jan 31 '16 at 14:44