Home > front end >  Java Generics - Upper Bounds through layers of inheritance
Java Generics - Upper Bounds through layers of inheritance

Time:04-28

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.

  • Related