Question

I thought I'd figured out generics with super. But I must be completely wrong:

With this simple example:

class Animal{}
class Dog extends Animal{}

This code works fine because we are passing in a super class of Dog:

static void addThis(ArrayList<? super Dog> a) {
    a.add(new Dog());
}
...
ArrayList<Animal> dogs=new ArrayList();
addThis(dogs);

However, what I don't understand is I thought this is the same thing:

ArrayList<? super Dog> dogs2=new ArrayList();
dogs2.add(new Animal());

But it fails to compile. What is the difference between the two?


By the way, I'd like to sneak in another question. Is there any difference between

// This...
ArrayList<Animal> dogs=new ArrayList();
// ... and this?
ArrayList<Animal> dogs=new ArrayList<Animal>();

Given type erasure removes it at compile time I figure it's the same thing as the compiler is checking the reference type. Is this correct?

Was it helpful?

Solution

It's not at all the same thing. In one case you're adding a Dog, in the other case you're adding an Animal.

In both cases you only know that Dogs are allowed, so the second case fails.

To answer your second question, there is a difference, and you should always use the second version. (In Java 7+, however, you can request the compiler to infer the generic type for you by writing new ArrayList<>().)

OTHER TIPS

Dog is an Animal so you can cast the ArrayList<? extends Dog> to ArrayList<Animal> but you can't go the other way since an Animal is not necessarily a Dog.

eg:

public class Cat extends Animal{}

Since this wouldn't make sense:

ArrayList<Dog> dogList = new ArrayList<Dog>();
dogList.add(new Cat());

You can't add an animal to the Dog list because the animal can be a cat.

This is an example of Java Type safety.

Simply put, List<? super Dog> is a list of objects which have super(parent) as Dog, NOT a list of objects which are super of Dog

Licensed under: CC-BY-SA with attribution
Not affiliated with StackOverflow
scroll top