Neil Walker
Neil Walker

Reputation: 6848

Difference between using `? super` in parameter and variable

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?

Upvotes: 0

Views: 99

Answers (3)

anoopelias
anoopelias

Reputation: 9538

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

Upvotes: 0

enrybo
enrybo

Reputation: 1785

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.

Upvotes: 0

Louis Wasserman
Louis Wasserman

Reputation: 198043

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<>().)

Upvotes: 4

Related Questions