Who could me explain this?
I have these couple of classes:
abstract class Animal {
public void eat() {
System.out.println("Animal is eating");
}
}
class Dog extends Animal {
public void woof() {
System.out.println("woof");
}
}
class Cat extends Animal {
public void meow() {
System.out.println("meow");
}
}
And this is the action:
import java.util.ArrayList;
import java.util.List;
public class TestClass {
public static void main(String[] args) {
new TestClass().go();
}
public void go() {
List<Dog> animals = new ArrayList<Dog>();
animals.add(new Dog());
animals.add(new Dog());
doAction(animals);
}
public <T extends Animal> void doAction(List<T> animals) {
animals.add((T) new Cat()); // why is it possible?
// Variable **animals** is List<Dog>,
// it is wrong, that I can add a Cat!
for (Animal animal: animals) {
if (animal instanceof Cat) {
((Cat)animal).meow();
}
if (animal instanceof Dog) {
((Dog)animal).woof();
}
}
}
}
This example compile without errors, and output is:
woof
woof
meow
But how can I add in list of Dog a Cat? And how the Cat is casted to Dog?
I use: java version "1.6.0_24". OpenJDK Runtime Environment (IcedTea6 1.11.1) (6b24-1.11.1-4ubuntu3)
Ok here's the deal with generics (anything that uses casting hackery might not be safe at runtime, because generics work by erasure):
You can assign a subtype parameterised the same way e.g
and you can add items that are the type of this parameter or its subclasses e.g
but you can only get out the type of the parameter:
Now, you can use a wild card to set an upper bound on the parameter type
But you can't add new items to this list
In your case you have a
List<T>
so it has a methodadd(T t)
so you can add if you cast toT
. ButT
has type bounded above byAnimal
so you shouldn't even be trying to add to this list, but it is treated as a concrete type and that's why it allows the cast. However this may throw aClassCastException
.And you can only retrieve items that are the upper bound type
Or you can set the lower bound parameter type
And you can add objects that are subtypes of the lower bound type
But all objects retrieved are of type Object