MyClass.java:9: incompatible types
found : java.util.Iterator<java.util.Map.Entry<java.lang.String,capture of ?>>
required: java.util.Iterator<java.util.Map.Entry<java.lang.String,?>>
Iterator<Entry<String,?>> it = map.entrySet().iterator();
^
In short: Iterator<Entry<String,capture of ?>> is not compatible with Iterator<Entry<String,?>>. The relevant lines of my program are:
Map<String,?> map;
Iterator<Entry<String,?>> it = map.entrySet().iterator();
Is "capture of ?" not a subtype of "?"? Yes, but that is not what we need here. We need the type arguments to be of the same type (you should already know that a List<String> is not a subtype of List<Object>).
This seems silly, isn't a wildcard the same type as it self? Yes, but here we have a wildcard and a type variable ("capture of ?" actually means that a wildcard has been converted into a type variable using capture conversion).
Then why bother with this capture conversion, my program is obviously correct and capture conversion gets in my way? No, your program is wrong. Capture conversion can actually help you understand why.
How? First of all you must learn how to read a wildcard aloud, e.g. read "Map<String,?>" as a Map from String to an unknown type. The second argument to Map is unknown but at some point the compiler needs to reason about a specific type, e.g., when you write "map.entrySet()". The compiler must reason about the specific type of the object "map" refers to at this point at runtime. The wildcard must not longer be wild (unknown) so the compiler captures a snapshot of "?" in an anonymous type variable at that point in the program, i.e., "capture of ?". So the difference between "?" and "capture of ?" is that the former refers to all possible types and the latter refers to a particular type at a particular point in you program.
I still do not see the point of all this? Ok, lets extend the above program a little bit, first we need a special (but perfectly sensible iterator):
class MyIterator<E> implements Iterator<E> {
Set<E> iteratedSet;
// other stuff left out for brevity
}
Now do this:
Entry<String,Number> unrelatedEntry; ... MyIterator<Entry<String,?>>mit = (MyIterator<Entry<String,?>>)it mit.iteratedSet.add(unrelatedEntry);
Now all of a sudden you have saved an Integer somewhere it might not belong!!! This will almost certainly lead to a class cast exception later in your program (e.g, if map referred to an instance of HashMap<String,String>).
OK, now I understand my problem. How do I solve it? That is simple: just write:
Map<String,?> map;
Iterator<? extends Entry<String,?>> it = map.entrySet().iterator();
Notice the added "? extends".
UPDATE: I have disabled comments. Please visit the
generics forum
instead.
Posted by Brian S O'Neill on June 11, 2004 at 08:17 AM PDT #
Posted by Peter Ah� on June 11, 2004 at 08:04 PM PDT #
Posted by Peter Ahé on June 11, 2004 at 08:07 PM PDT #
Posted by Peter Ahé on June 11, 2004 at 08:09 PM PDT #
Posted by Keith Lea on July 15, 2004 at 09:25 PM PDT #
Posted by Angelika Langer on August 02, 2004 at 10:16 PM PDT #
How do I say "List of unbounded wildcard" without using angle brackets?
In the comment above it should read: That would mean that a "List of unbounded wildcard" is a list of elements of all possible types, while in fact it is a list of one particular (unknown) type.
Posted by Angelika Langer on August 02, 2004 at 10:22 PM PDT #
List<Foo> is a subtype of Collection<Foo>, List<String> is not a subtype of List<Object>
class Test {
List<?> l;
void m() {
l.add(l.remove(0));
}
}
<div>It would apparently be safe to allow this to compile. We just removed
an element from a list and now we put it back. But what happens if a
different thread has changed the field l between the call to l.remove
and l.add. Then if the unknown type of the object referenced by l at
the time l.remove is called could be List<Integer> meaning that
we just removed an Integer from that list. Now the other thread gets
to execute, so l could point to an entirely different List,
e.g. List<String>. Then we call l.add with an Integer on a
List<String>.</div>
<div>In this example we actually captured the List<?> twice, first
when we call l.remove, next when we call l.add (technically, the
capture happens exactly when we "dot into" l). I just argued that the
unknown types captured at those those points could be compeletely
unrelated types. That is what I mean when I say "all possible types".
A variable declared to be a List<?> can be a List of any
possible type. Maybe I should have said "any", not "all". Please
forgive me, English is my second language.</div>
<div>So can you harness wildcard capture conversion to do something similar
to the method m above? Yes, write a generic method:</div>
class Test {
List<?> l;
void m() {
m2(l);
}
<T> static void m2(List<T> l2) {
l2.add(l2.remove(0));
}
}
<div>Here we only capture the type of l once, namely when we call m2 from
m. Notice that for the duration of the call to m2, we have a name for
the unknown, captured type: T.</div>
Posted by pprun on September 27, 2004 at 12:34 AM PDT #
Your question is a bit unclear, but I guess that you wonder what is wrong with this line:
ArrayList<Object> = new ArrayList();The problem is that you left out the type parameters on the second line:
ArrayList<Object> = new ArrayList<Object>();
public static <T> Predicate<T> andPredicate(Predicate<? super T> predicate1, Predicate<? super T> predicate2) {
return AndPredicate.getInstance(predicate1, predicate2);
}
And this method calls (in AndPredicate):
public static <T> Predicate<T> getInstance(Predicate<? super T> predicate1, Predicate<? super T> predicate2) {
if (predicate1 == null || predicate2 == null) {
throw new IllegalArgumentException("Predicate must not be null");
}
return new AndPredicate<T>(predicate1, predicate2);
}
The constructor that it calls looks like:
public AndPredicate(Predicate<? super T> predicate1, Predicate<? super T> predicate2) {
super();
iPredicate1 = predicate1;
iPredicate2 = predicate2;
}
This does not compile, giving the error:
Error: line (264) <T>getInstance(org.apache.commons.collections.Predicate<? super T>,org.apache.commons.collections.Predicate<? super T>) in org.apache.commons.collections.functors.AndPredicate cannot be applied to (org.apache.commons.collections.Predicate<capture of ? super T>,org.apache.commons.collections.Predicate<capture of ? super T>)How should I resolve this? I can't think of a way of retooling it so that I can still ensure that the two predicates can act on objects of type T or objects of T's super-class.
Thanks in advance,
John Watkinson
Posted by John Watkinson on May 05, 2005 at 03:04 PM PDT #
return AndPredicate.<T>getInstance(predicate1, predicate2);
Posted by Matthijs Snel on May 14, 2005 at 12:18 PM PDT #
SortedSet<? extends Group<Integer>> ss = Group.createGroups(a);
Posted by Peter von der Ahé on May 16, 2005 at 03:04 PM PDT #
-------------------------------------------------------
// public interface Parent { // This does not work. Why?
public interface Parent<D extends Child> { // This works.
List<Child> getChildren();
}
-------------------------------------------------------
public interface Child {
}
-------------------------------------------------------
public class ParentImpl1 implements Parent {
private List<ChildImpl1> children;
public List<ChildImpl1> getChildren() {
return children;
}
}
-------------------------------------------------------
public class ParentImpl1 implements Parent {
private List<ChildImpl1> children;
// In our case, this must return implementation and not interface
public List<ChildImpl1> getChildren() {
return children;
}
}
-------------------------------------------------------
public class ChildImpl1 {
}
-------------------------------------------------------
public class Test {
public static void loopChildren(Parent p) {
// This works
final List<Child> children = p.getChildren();
for(Child child : children) {
}
// This does not work. Why?
/*
for(Child child : p.getChildren()) {
}
*/
}
}
-------------------------------------------------------
Posted by Mattias Jiderhamn on October 06, 2005 at 04:07 AM PDT #
Posted by Peter von der Ahé on October 06, 2005 at 04:19 AM PDT #