I have the following Generic class:
import java.util.ArrayList;
import java.util.List;
public class GenericRaw<T> {
public List<String> get() {
return new ArrayList<>();
}
}
Let us consider the case of its usage:
public class Usage {
public void doSomething() {
GenericRaw base = new GenericRaw();
for (String x : base.get()) { }
}
}
For this code Idea doesn't give any compilation error but Java compiler itself does:
java: incompatible types required: java.lang.String found: java.lang.Object
Reproducible on JDK 1.6.0_33 as well as on JDK 1.7.0_17.
Can someone help me with the explanation of this issue?
Results of my investigations. The following variants can be successfully compiled:
public void doSomething() { GenericRaw<?> base = new GenericRaw(); for (String x : base.get()) { } }
or even:
public void doSomething() { GenericRaw base = new GenericRaw(); List<String> list = base.get(); for (String x : list) { } }
Can someone help me with the explanation of this issue?
Sure. It's following the JLS's description of raw types, in section 4.8:
To facilitate interfacing with non-generic legacy code, it is possible to use as a type the erasure (§4.6) of a parameterized type (§4.5) or the erasure of an array type (§10.1) whose element type is a parameterized type. Such a type is called a raw type.
The erasure of GenericRaw<T>
is:
public class GenericRaw {
public List get() { ... }
}
because:
Type erasure also maps the signature (§8.4.2) of a constructor or method to a signature that has no parameterized types or type variables. The erasure of a constructor or method signature s is a signature consisting of the same name as s and the erasures of all the formal parameter types given in s.
The type parameters of a constructor or method (§8.4.4), and the return type (§8.4.5) of a method, also undergo erasure if the constructor or method's signature is erased.