Reputation: 230
I don't understand why this code compiles:
public void test(Collection<? extends Enum> enumCollection) {
for (Enum e : enumCollection) {
}
}
and this one does 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 of Enum
in all cases, so why am I getting a compilation error with the iterator and why does it work with a for-each loop?
Upvotes: 4
Views: 718
Reputation: 65811
I often find that the adage if you need to use ? in your generic you are probably doing something wrong applies.
This works fine:
public <T extends Enum<T>> void test(Collection<T> enumCollection) {
for (Enum e : enumCollection) {
}
Iterator<T> iterator = enumCollection.iterator();
}
Your problem is that you are expecting generics to act like ordinary code where an ArrayList
is also a List
. It is not designed for that. Generics are to ensure that you are using the same type, not just some compatible type.
In your case - to match the ? extends Enum
you could use:
Iterator<?> iterator = enumCollection.iterator();
which works fine.
Your types do not match - and generics are there to make sure they do.
Remember that ?
does not mean I don't care what type it is it means I don't want to know what type it is. Using ?
in a generic type and then expecting to be able to make use of the type is just silly.
Upvotes: 8
Reputation: 11910
Concerning the for loop, according to the JLS 14.14.2, the following code:
public void test(Collection<? extends Enum> enumCollection) {
for (Enum e : enumCollection) {
}
}
Will be translated to 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 problem. As you can see, you will never have an Iterator<Enum>
directly, but instead an Iterator
of whatever you said is the type of the elements in your collection.
The relevant part of the JLS is:
If the type of Expression is a subtype of Iterable for some type argument X, then let I be the type java.util.Iterator; otherwise, let I be the raw type java.util.Iterator.
The storage in an Enum
variable is only done for each element, where it's relevant.
Upvotes: 3