With a single layer of inheritance I can do something like this:
// Dog extends Animal
List<Dog> dogs = ...;
// Cat extends Animal
List<Cat> cats = ...;
List<? extends Animal> animals = new ArrayList<>();
animals.addAll(cats);
animals.addAll(dogs);
I can do this without casting, which is nice.
But what if I have a scenario like the following?
// Plant extends LivingBeing
List<Plant> plants = ...;
// Animal extends LivingBeing
// Cat extends Animal
List<Cat> cats = ...;
List<? extends LivingBeing> livingThings = new ArrayList<>();
// This is fine
lvingThings.addAll(plants);
// FIXME: Fails because Cat doesn't directly extend LivingBeing
livingThings.addAll(cats);
Is there a way to specify an upper bound that is not a direct parent of all members of the list, so that I can avoid casting?
CodePudding user response:
Your first example doesn't compile. Both are caused by the ? extends
part. The issue is that as soon as the initialization is done, the compiler already forgot the actual type. That means that after initializing livingThings
, the compiler thinks it can be a List<LivingBeing>
, List<Animal>
or List<Cat>
(all of which would allow adding cats), but also List<Dog> or
List`, which don't allow cats.
If you want a list with things that can be any type of living being, you must declare it as such: List<LivingBeing>
. Otherwise you can't add anything anymore except null
.
The latter is true for any Collection<? extends T>
for any type T
. The only value that is safe for any type that matches ? extends T
is null
.