Allows you to first view the source:
public void putAll(final Map<? extends K, ? extends V> mapToCopy) { for (Map.Entry<? extends K, ? extends V> entry : mapToCopy.entrySet()) { } }
Internally (and in Runtime), this will compile and work like:
public void putAll(final Map mapToCopy) { for (Iterator<Map.Entry> iterator = mapToCopy.iterator; iterator.hasNext();) { } }
where ? extends K ? extends K and ? extends V ? extends V will be replaced with some real types after type erasure. The compiler will know what type is of this type and will not raise an Exception for type incompatibility.
On the other hand, if you reorganize the source for this,
public void putAll(final Map<? extends K, ? extends V> mapToCopy) { Set<Entry<? extends K, ? extends V>> entrySet = mapToCopy.entrySet(); ^^^^^^^^ for (Map.Entry<? extends K, ? extends V> entry : entrySet) { } }
then the compiler will have no evidence that the entrySet is of the same type as Map.Entry<? extends K, ? extends V> Map.Entry<? extends K, ? extends V> Map.Entry<? extends K, ? extends V> , simply because the wildcard ( ? ) always means something is unknown , that is, there is no guarantee that the wildcard from the value of the entrySet key will be the same as the value of the entry key (from the loop). Not being 100% sure that the types are compatible, the compiler generates a compile-time error **, although ** you can be sure that these types will be the same at runtime.
source share