Ankur
Ankur

Reputation: 51100

Why can't a method take a Collection<subClass> when the method's signature is defined as Collection<class>

I have a method that takes a list of SResource objects

public static List<STriple> listTriples(List<SResource> subjects){
//... do stuff
}

Why can't I do this

List<IndexResource> resultsAsList = new ArrayList<IndexResource>();
    resultsAsList.addAll(allResults.keySet()); // I could possible not use lists and just use sets and therefore get rid of this line, but that is a different issue
List<STriple> triples = new ArrayList<STriple>();
    triples = TriplesDao.listTriples(resultsAsList);

(The compiler tells me I have to make triples use SResource objects.)

When IndexResource is a subclass of SResource

public class IndexResource extends SResource{ 
// .... class code here
}

I would have thought this has to be possible, so maybe I am doing something else wrong. I can post more code if you suggest it.

Upvotes: 6

Views: 4431

Answers (3)

Dan Grahn
Dan Grahn

Reputation: 9404

For those who are unable to add wildcards, this should work.

List<Integer> list = new ArrayList<Integer>();
new ArrayList<Number>(list);

Upvotes: 1

dlev
dlev

Reputation: 48596

You can do it, using wildcards:

public static List<STriple> listTriples(List<? extends SResource> subjects){
    //... do stuff
}

The new declaration uses a bounded wildcard, which says that the generic parameter will be either an SResource, or a type that extends it.

In exchange for accepting the List<> this way, "do stuff" can't include inserting into subjects. If you're just reading from the subjects in the method, then this change should get you the results you want.

EDIT: To see why wildcards are needed, consider this (illegal in Java) code:

List<String> strings = new ArrayList<String>();
List<Object> objList = string; // Not actually legal, even though string "is an" object
objList.add(new Integer(3)); // Oh no! We've put an Integer into an ArrayList<String>!

That's obviously not typesafe. With wilcards, though, you can do this:

List<String> strings = new ArrayList<String>();
string.add("Hello");
List<? extends Object> objList = strings; // Works!
objList.add(new Integer(3)); // Compile-time error due to the wildcard restriction

Upvotes: 23

Sanjay T. Sharma
Sanjay T. Sharma

Reputation: 23208

You can't do this because generics are not "covariant" i.e. a List<Integer> is not a sub-class of the List<Number> though Integer is a sub-class of Number.

Upvotes: 5

Related Questions