Reputation: 2910
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
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
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
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