javanerd
javanerd

Reputation: 9

Java wildcard generic problem: Compiler assumes different types for same object

I have a problem related to JAVA wildcards and generics. I do not want to post my own complex code, so I will use the Collection interface for demonstration:

Collection<String> stringCollection = new HashSet<String>();
stringCollection.add("1");
stringCollection.add("2");
stringCollection.add(stringCollection.iterator().next());

Here, the last line is no problem. add() requires a string and next() returns a string.

But:

Collection<?> anyCollection = stringCollection;
anyCollection.add(anyCollection.iterator().next());

Using the wildcard, Eclipse tells me the error

The method add(capture#19-of ?) in the type Collection is not applicable for the arguments (capture#20-of ?)

But why? I need to use the wildcarded Collection. Somehow Eclipse just doesn't get that next() definitely MUST return an object exactly of the type add() requires.

Is there any way to fix this without getting an error? For sure, a cast to (capture#20-of ?) doesn't work.

Upvotes: 0

Views: 955

Answers (3)

ColinD
ColinD

Reputation: 110084

You can't add anything but null to a Collection<?>. Yes, you know that any element that's already in the collection should be able to be added to it, but the type doesn't reflect that. <?> and <? extends Foo> should only be used when you only need to retrieve objects from the collection and not add to it. Can you show why you need to use a wildcard as opposed to, say, Collection<E>?

(I assume you know this, but in your example your collection is a Set and as such, adding any element that's already in it will do nothing.)

Edit:

From your comment, it sounds to me like you don't want a wildcard but just a generic method:

public <T extends PersistenceObject> void doSomething(Dao<T> dao) {
  T o = dao.createNew();
  // ...
  dao.save(o);
}

The same would be true of a method that wants to re-add the first element of a Collection to it:

public <E> boolean reAddFirst(Collection<E> collection) {
  return collection.add(collection.iterator().next());
}

The specific type parameter (rather than a wildcard) tells the compiler that the type retrieved from the object is the same type that the object expects to be passed to its method.

Upvotes: 4

Hurda
Hurda

Reputation: 4715

Make anyCollection collection of Object

Collection<Object> anyCollection = stringCollection;

This should work

Upvotes: 0

Suraj Chandran
Suraj Chandran

Reputation: 24801

You can't add a string object in to a collection of type Collection<?>, because the type Collection itself means that you dont know the type of the collection, hence the compiler won't allow you to add arbitrary types in it.

One way to fix this is to cast it like so:

    Collection<?> c = new HashSet<String>();
    Collection strCol = (Collection<String>)c;
    strCol.add("Suraj");

Upvotes: 0

Related Questions