InDaPond
InDaPond

Reputation: 572

Shadowing / Scope of Variables

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.

Upvotes: 1

Views: 130

Answers (3)

Has QUIT--Anony-Mousse
Has QUIT--Anony-Mousse

Reputation: 77495

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.

Upvotes: 2

Fergus Rataporn
Fergus Rataporn

Reputation: 103

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

Upvotes: 1

Dev Blanked
Dev Blanked

Reputation: 8885

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.

Upvotes: 1

Related Questions