Search code examples
javagenericscompilationtype-erasureincompatibletypeerror

Java generics incompatible types compilation error for generic static method call in Oracle Java SE 8u20 JDK


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.


Solution

  • 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:

    Can't cast to to unspecific nested type with generics