Any simple way to explain why I cannot do ListAnimal animals = new ArrayListDog()?
Imagine you create a list of Dogs. You then declare this as List<Animal> and hand it to a colleague. He, not unreasonably, believes he can put a Cat in it.
He then gives it back to you, and you now have a list of Dogs, with a Cat in the middle of it. Chaos ensues.
It's important to note that this restriction is there due to the mutability of the list. In Scala (for example), you can declare that a list of Dogs is a list of Animals. That's because Scala lists are (by default) immutable, and so adding a Cat to a list of Dogs would give you a new list of Animals.
Is ListDog a subclass of ListAnimal? Why are Java generics not implicitly polymorphic?
No, a List<Dog>
is not a List<Animal>
. Consider what you can do with a List<Animal>
- you can add any animal to it... including a cat. Now, can you logically add a cat to a litter of puppies? Absolutely not.
// Illegal code - because otherwise life would be Bad
List<Dog> dogs = new ArrayList<Dog>(); // ArrayList implements List
List<Animal> animals = dogs; // Awooga awooga
animals.add(new Cat());
Dog dog = dogs.get(0); // This should be safe, right?
Suddenly you have a very confused cat.
Now, you can't add a Cat
to a List<? extends Animal>
because you don't know it's a List<Cat>
. You can retrieve a value and know that it will be an Animal
, but you can't add arbitrary animals. The reverse is true for List<? super Animal>
- in that case you can add an Animal
to it safely, but you don't know anything about what might be retrieved from it, because it could be a List<Object>
.
Why can't List? extends Animal be replaced with ListAnimal?
A List<Animal>
is a List
to which you can add any Animal
(or null), and everything you take out of it will be an Animal
.
A List<? extends Animal>
is a list which contains only a specific subclass of Animal
(or null), and you don't know which one; this allows you to treat everything you take out of it as an Animal
, but you aren't allowed to add anything to it (except for literal null
).
A List<? extends Animal>
can't act as a List<Animal>
, because that would allow you to do this:
List<Cat> listOfCats = new ArrayList<>();
List<? extends Animal> listOfSomeAnimals = listOfCats; // Fine.
List<Animal> listOfAnimals = listOfSomeAnimals; // Error, pretend it works.
listOfAnimals.add(new Dog());
Now, because listOfCats
, listOfSomeAnimals
and listOfAnimals
are all the same list, the Dog
has been added to listOfCats
. As such:
Cat cat = listOfCats.get(0); // ClassCastException.
Casting ListAnimal to ListDog
Generics inheritance is little different than java inheritance principle. You need to use ?
(wildcards)
List<? extends Animal> dogList = getAnimalList();
EDIT:
Wildcard Guidelines:
- An "in" variable is defined with an upper bounded wildcard, using the extends keyword.
- An "out" variable is defined with a lower bounded wildcard, using the super keyword.
- In the case where the "in" variable can be accessed using methods defined in the Object class, use an unbounded wildcard.
- In the case where the code needs to access the variable as both an "in" and an "out" variable, do not use a wildcard.
Is it possible to get a list of Dog from a list of Animal without a cast?
Ok, it seems absurd but the problem was in the JSF code:
<ui:repeat var="animal" value="#{bean.animals.get('dogs')}" varStatus="status">
I don't know why, but changing var="animal"
to anything else works. I do not need any cast.
Related Topics
Java: Infinite Loop Using Scanner In.Hasnextint()
Value Change Listener for Javafx's Textfield
Passing an Array or List to @Pathvariable - Spring/Java
The Value for the Usebean Class Attribute ... Is Invalid
Using PDFbox to Write Utf-8 Encoded Strings to a PDF
Calling Base Class Overridden Function from Base Class Method
Howto Extract Mimetype from a Byte[]
Java Unreachable Catch Block Compiler Error
Accessing a File Inside a .Jar File
String S = New String("Xyz"). How Many Objects Has Been Made After This Line of Code Execute
Efficiently Finding the Intersection of a Variable Number of Sets of Strings
Concurrent Threads Adding to Arraylist at Same Time - What Happens
How to Use Session in Jsp Pages to Get Information
Why Doesn't Java.Util.Collection Implement the New Stream Interface
How to Check a Timeperiod Is Overlapping Another Time Period in Java