Basically what the title says, but some elaboration. I have a SuperClass with a couple of SubClasses. I needed an ArrayList to hold both types of Subclasses so hence the Arr
All of the objects retain their own class identity, but the code that uses the ArrayList
isn't directly aware of it. As far as it's concerned, the ArrayList
only holds references to SuperClass
-type objects, and it can only call SuperClass
's methods on objects it retrieves from it.
The calling code can use instanceof
or similar techniques to find out if a particular object in a collection is of a subtype, but this is usually bad practice, since it usually indicates mixing of the different levels of abstraction. The one case where this is generally considered reasonable is if the subclass has some optional high-performance characteristic that the caller can take advantage of (and that measurement has determined is worth complicating the code for); one example might be that while List
's get()
method is has no performance guarantees, some implementations, like ArrayList
, also implement RandomAccess
, which indicates that there's no performance penalty to using get()
in any order.
When you have some ArrayList and you fill it with things that extend SuperClass you have to check instanceof and cast to get to the methods specific to those subclasses.
Example:
ArrayList<Animal> animals = new ArrayList<Animal>;
animals.add(new Duck());
animals.add(new Cow());
animals.add(new Horse());
for (Animal animal : animals)
if (animal instanceof Horse) {
Horse horse = (Horse)animal;
horse.gallop();
}
The objects themselves are still a subclass
, but when you get them out of the collection it only knows about the superclass
so it can't tell you which is which, it has to pick the common denominator.
If you know exactly that a specific index holds an object of type Subclass
you can just cast it:
Subclass myObject = (Subclass) list.get(0);
System.out.println(myObject.getQuantity());
And it should work.
And a safer way requires testing if the object is really what you think it is:
SuperClass myObject = list.get(0);
if ( myObject instanceof Subclass) {
Subclass mySubObject = (Subclass) myObject;
System.out.println(mySubObject.getQuantity());
}
The first example raises an exception if the object is not of type Subclass
, the second one wouldn't since it tests before to make sure.
What you need to understand here is that SuperClass myObject = list.get(0)
is not the object itself, but a reference to access the object in memory. Think about it as a remote that allows you to control your object, in this case, it's not a fully featured remote, since it doesn't show you all your object can do, so you can switch to a better one (as in Subclass myObject = (Subclass) list.get(0)
) to be able to access all features.
I'd surely recommend the Head First Java book as it covers this stuff in great detail (and I stole this remote example from there).