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?

+3


source to share


2 answers


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.

+7


source


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.

+2


source







All Articles