Upper bounded wildcard, iterator and every loop
I don't understand why this code compiles:
public void test(Collection<? extends Enum> enumCollection) {
for (Enum e : enumCollection) {
}
}
but this is not:
public void test(Collection<? extends Enum> enumCollection) {
Iterator<Enum> iterator = enumCollection.iterator();
//Required: Iterator<Java.lang.Enum>
//Found: Iterator<capture<? extends Java.lang.Enum>>
}
? extends Enum
should be a subtype Enum
in all cases, so why am I getting a compile error with an iterator and why does it work with a for-each loop?
source to share
I often find that saying if you need to use? in your general case, you are probably doing something wrong.
This works great:
public <T extends Enum> void test(Collection<T> enumCollection) {
for (Enum e : enumCollection) {
}
Iterator<T> iterator = enumCollection.iterator();
}
Your problem is that you expect generics to act like normal code, which ArrayList
is where it also is List
. It is not meant to be. Generators must ensure that you are using the same type , not just some compatible type.
In your case - for matching, ? extends Enum
you can use:
Iterator<?> iterator = enumCollection.iterator();
which works great.
Your types don't match - and generics exist to make sure they do.
Remember, that ?
doesn't mean I don't care what type it means, that I don't want to know what type it is. Using ?
in a generic type and then expecting to be able to use that type is just silly.
source to share
As for the for loop, according to JLS 14.14.2 , the following code:
public void test(Collection<? extends Enum> enumCollection) {
for (Enum e : enumCollection) {
}
}
It will be translated something like this:
public <T extends Enum> void test(Collection<T> enumCollection) {
for (Iterator<T> iterator = enumCollection.iterator(); iterator.hasNext();) {
Enum e = (T) iterator.next();
}
}
Which compiles without issue. As you can see, you will never Iterator<Enum>
directly have , but instead Iterator
, what you said is the type of the items in your collection.
Relevant part of the JLS:
If the type of the expression is a subtype of Iterable for some argument of type X, then let me be of type java.util.Iterator; otherwise, let me be a raw java.util.Iterator type.
Storing in a variable Enum
is done only for each item where it matters.
source to share