When compiling the code below with the Oracle Java SE 8u20 JDK, the first three assignments compile fine (for the works*
variables), but the fourth assignment (for the fails1
variable) generates the following compilation error:
Error:
incompatible types: Set<Set<Object>> cannot be converted to Set<Set<? extends Object>>
Code:
import java.util.Set;
import java.util.Collections;
...
Set<? extends Object> works1 = Collections.<Object>emptySet();
Set<Set<Object>> works2 = Collections.<Set<Object>>emptySet();
Set<Set<? extends Object>> works3 = Collections.<Set<? extends Object>>emptySet();
Set<Set<? extends Object>> fails1 = Collections.<Set<Object>>emptySet();
I assume that this is correct (probably due to some sort of type erasure defined in the Java language specification), rather than being a bug, but I don't know for sure.
Does anyone know why fails1
fails to compile? A reference to the applicable part of the Java spec, or to a JDK bug report, would be appreciated.
Thanks for any help.
Anything between <
& >
is type invariant unless you use a ?
wildcard.
The types of Set<? extends Object>
& Set<Object>
are different, and therefore need type variance to be considered compatible.
If they're at the top level, as for works1
, the top-level Set
is outside the <
& >
, so the normal Java type variance works, but for fails1
, they're inside the <
& >
, so the types are invariant.
Type variance can be enabled within the <
& >
by changing the outermost part of the type declaration from Set<Set<...>>
Set<? extends Set<...>>
.
Thus, the following code compiles correctly:
Set<? extends Set<? extends Object>> works4 = Collections.<Set<Object>>emptySet();
I derived my answer from the answer to the following question (which was mentioned above by @MarkoTopolnik):
multiple nested wildcard - arguments not applicable
The answer to the following question provided a more detailed explanation: