Flying_Banana
Flying_Banana

Reputation: 2910

Accessing overridden values in child class

Suppose I have an abstract parent class:

public abstract class Bar {
    public int count = 0;
}

Now I have several concrete subclasses. Suppose one is:

public class Foo extends Bar {
    public int count = 1;
}

Now I want to iterate through a collection of children extending the abstract class. When I ask their values of count, however, I find that what I get is the parent's initialised value, instead of the one initialised in the child:

List<Bar> l = new ArrayList<Bar>();
l.add(new Foo());
for (Bar b : l) {
    System.out.println(b.count.toString()); // This always gives 0.
}

I am obviously using the class model wrong. What is the correct way so I can get the values initialised by the subclasses?

Upvotes: 0

Views: 44

Answers (3)

NiziL
NiziL

Reputation: 5140

In complement of the Mena's answer, I want to point out that shadowing a superclass attribute in a subclass is often a mess, and clearly not a good object-oriented design.

If you want your Foo and Bar objects to have different value, why not using a constructor to initialize the count field differently ? This is the most straightforward way to achieve your requirement.

public class Bar {
  public int count ;

  public Bar() {
    count = 0;
  }
}

public class Foo extends Bar {
  public Foo() {
    count = 1
  }
}

With this code, you could easily take advantage of polymorphism to loop over a List<Bar> and collect count, without having to cast, or without defining a getter for each subclass of Bar.

Upvotes: 0

Dragan Bozanovic
Dragan Bozanovic

Reputation: 23562

Access to fields is resolved at compile time. There is no concept like fields overriding, there is only fields shadowing: The count field in Foo shadows the inherited count field in Bar.

To avoid shadowing and confusion, you should rename the field in the inherited class to fooCount for example.

Nevertheless, if you want to print the count field defined in Foo, you could do:

for (Bar b : l) {
    if (b instanceof Foo) {
        System.out.println(((Foo)b).count.toString()); // This always gives 1.
    } else {
        System.out.println(b.count.toString()); // This always gives 0.
    }
}

Of course, as suggested in other answers, you should rethink whether this design is good (and the first signal that it may not be good is the usage of instanceof operator), and use polymorphism to achieve the same goal in a more readable and maintainable way.

Upvotes: 1

Mena
Mena

Reputation: 48434

Your iteration references the type Bar, as parametrized type of your List.

As such it will get the count propery of Bar, hidden by Foo's count.

That's why you get 0.

If you want dynamic variable resolution, implement and override a method returning count.

Which in turn would help with your encapsulation design if you also set count with more appropriate access modifiers.

Final note

Quoting your comment:

I prefer sticking to fields, because I have a lot of these fields

Implementing getters and setters for your fields should be trivial.

In fact, you get automatic drafts or fully implemented methods by just following a quick wizard in any respectable IDE, once you've declared your fields.

As a general rule, you may consider to not use the template getters as is, if your fields are mutable.

As another general rule, you may consider not to use the template setters implemented as is, if your fields require validation before setting.

I suggest for that matter that you have a closer look at the concept of encapsulation.

Upvotes: 4

Related Questions