Java泛型是一个全有或全无的决定吗?

Fra*_*kPl 9 java generics

我有以下代码:

public class Main {
    public static void main(String[] args) {
        Generic generic = new Generic<Integer>(5);
        List<String> stringList = generic.getStringList(); // this line is where the compiler complains
    }
}

public class Generic<T> {
    private T member;

    public Generic(T member) {
        this.member = member;
    }

    public T getMember() {
        return member;
    }

    public List<String> getStringList() {
        return new ArrayList<String>();
    }
}
Run Code Online (Sandbox Code Playgroud)

请注意,类Generic使用泛型类型参数声明,但generic方法中的变量main属于擦除类型,即没有类型参数.我不明白的是为什么编译器抱怨分配的行List<String>:

Warning:(6, 56) java: unchecked conversion
  required: java.util.List<java.lang.String>
  found:    java.util.List
Run Code Online (Sandbox Code Playgroud)

该方法明确返回a List<String>,独立于类的泛型参数.这就是变量所stringList期望的.似乎不在类级别上使用泛型参数来generic关闭所有泛型处理,而不仅仅是取决于类的类型参数.

我正在使用标准的Oracle Java 1.7.0_55编译器,如果这很重要的话.

我不是在问如何摆脱警告.我知道我应该声明变量类型Generic<Integer>,或者可以使用@SuppressWarnings("unchecked").我的问题如下:

这种行为是否有记录?

这种奇怪行为的原因是什么?

Jon*_*eet 13

当您使用类型的擦除时,它会删除所有泛型的痕迹 - 而不仅仅是类型参数的使用T.所以你的generic变量就好像它指的是这种类型:

// After type erasure
public class Generic {
    private Object member;

    public Generic(Object member) {
        this.member = member;
    }

    public Object getMember() {
        return member;
    }

    public List getStringList() {
        return new ArrayList();
    }
}
Run Code Online (Sandbox Code Playgroud)

这在JLS中有记录 - 从4.6节开始并按照链接进行操作.它并不像它可能那样清晰,但它记载.

原因是,如果您使用原始类型,编译器希望您根本不了解泛型 - 因为它可能正在编译传统的Java-5之前的代码.随着时间的推移,这被证明有点不切实际,但我相信这是规范的动机.