为何Java原始类型会擦除已具体化泛型成员的类型?
原始类型使用时,为何已具体化的泛型成员也被擦除?
示例代码
import java.util.ArrayList; import java.util.List; public class MyTemplate<T> { T parameterizedObj; List<String> stringList; public static void main(String[] args) { String a = new MyTemplate().getStringList().get(0); } public List<String> getStringList() { if (stringList == null) { stringList = new ArrayList<>(); stringList.add("Hello"); } return stringList; } }
编译错误
/home/***/test/src/main/java/MyTemplate.java:10:56 java: incompatible types: java.lang.Object cannot be converted to java.lang.String
疑问
当在第10行以new MyTemplate()的形式将MyTemplate作为原始类型使用时,能理解T parameterizedObj的类型会被擦除为Object,但无法理解已被具体化为List<String>的List<String> stringList为何会被擦除为List。查阅了原始类型和类型擦除的相关文档,未找到针对这类场景的说明。
解答
这是Java原始类型的规则:只要将泛型类作为原始类型使用,整个类的所有泛型相关信息都会被完全擦除,不仅限于类本身的类型参数T。
换句话说,当你用new MyTemplate()创建原始类型实例时,编译器会忽略这个类中所有的泛型签名——哪怕成员变量或方法返回值用的是具体的泛型类型(比如List<String>),也会被退化为擦除后的原始类型(List)。所以getStringList()的返回值会被视为List,调用get(0)自然返回Object,无法直接赋值给String,导致编译错误。
解决方法
只需避免使用原始类型,改用带类型参数的实例化方式即可:
- 使用菱形语法(Java 7+支持):
new MyTemplate<>() - 显式指定类型参数:
new MyTemplate<Object>()
这样编译器会保留List<String>的类型信息,get(0)返回的就是String,编译错误会消失。
内容的提问来源于stack exchange,提问作者Fengtao Ding
相关产品推荐
相关产品推荐

