fortran
fortran

Reputation: 76057

Incompatible generic wildcard captures

in the following snippet:

package test;

import java.util.Collection;
import java.util.Iterator;
import java.util.Map;

public class WildcardsTest<K, V> {
    private Iterator<Map.Entry<K, ? extends Collection<V>>> iterator;
    public WildcardsTest(Map<K, ? extends Collection<V>> map) {
        iterator = map.entrySet().iterator();
        /* Type mismatch: cannot convert from
           Iterator<Map.Entry<K,capture#1-of ? extends Collection<V>>> to
           Iterator<Map.Entry<K,? extends Collection<V>>> */
    }
}

The assignment is incorrect, although the types seem to match exactly.

I've devised a dirty workaround by specifying the type of the Collection as another generic parameter, like this:

public class WildcardsTest<K, V, C extends Collection<V>> {
    private Iterator<Map.Entry<K, C>> iterator;
    public WildcardsTest(Map<K, C> map) {
        iterator = map.entrySet().iterator();
    }
}

But that C parameter is really a "don't care" type that only complicates the API, is there any way to get rid of it while maintaining type safety?

Thanks.

Upvotes: 3

Views: 2050

Answers (2)

Sean Patrick Floyd
Sean Patrick Floyd

Reputation: 298818

Do it like this and it will work:

private final Iterator<? extends
    Map.Entry<K, ? extends Collection<V>>
> iterator;

You can still use the iterator like this:

public void foo(){
    while(iterator.hasNext()){
        Entry<K, ? extends Collection<V>> entry = iterator.next();
        Collection<V> value = entry.getValue();
    }
}

For reference, read the get and put principle (originally from Java Generics and Collections)

Upvotes: 4

aioobe
aioobe

Reputation: 420921

The assignment is incorrect, although the types seem to match exactly.

The two ?-wildcards can be bound to two different classes. Put it this way, it is quite obvious that there is a type mismatch:

private Iterator<Map.Entry<K, ArrayList<V>>> iterator;
public WildcardsTest(Map<K, HashSet<V>> map) {
    iterator = map.entrySet().iterator();
}

When you introduce the C, you "force them" to refer to the same class.

Upvotes: 2

Related Questions