为什么没有指定泛型类型时不返回基类型?

MAR*_*REK 5 java generics java-8

我有这样的代码:

public class A<T extends String> {

    T field;
    List<T> fields;

    public T getField() {
        return field;
    }

    public List<T> getFields() {
        return fields;
    }

    public static void test(){
        A a = new A();
        String s = a.getField();
        List<String> ss = a.getFields();
    }
}
Run Code Online (Sandbox Code Playgroud)

为什么在A没有泛型类型的getFiled情况下创建返回StringgetFileds返回List<Object>

我必须定义AA<String> a = new A<>()使其正常工作.

谢谢,

Ole*_*hov 6

T声明中类型参数的擦除T fieldString因为T已经绑定:

<T extends String>
Run Code Online (Sandbox Code Playgroud)

而且任何subtype一个String也是String1.

但是,这不适用于通用List<T>.它源于仿制药不协变的事实:

List<String> str = new ArrayList<String>();
List<Object> obj = str; // Error: incompatible types (even though String extends Object)
Run Code Online (Sandbox Code Playgroud)

的擦除List<T>在声明List<T> fieldsList,特别是因为List<T>可以保持String或它的subtypes1.并且鉴于它A是原始类型,编译器无法猜测getFields()方法返回的列表中的元素类型.

无论如何,这行代码:

List<T> fields;
Run Code Online (Sandbox Code Playgroud)

编译(擦除通用类型)到:

List fields;
Run Code Online (Sandbox Code Playgroud)

结果,当你写:

A a = new A();  instead of  A<String> a = new A<>();
Run Code Online (Sandbox Code Playgroud)

你失去了类型安全性并获得"未经检查的分配"警告 - 在这种情况下,编译器不能保证它fields list完全是List<String>:

List<String> list = a.getFields(); // Unchecked assignment: 'List' to 'List<String>' ...
Run Code Online (Sandbox Code Playgroud)

PS不要使用原始类型!


1 - 如您所知,String课程是最终的,不能延长.如果您愿意,可以将其替换为任何可以扩展的类型.

  • +1 ...换句话说,给定约束,无论`getField`返回什么都可以赋值给`String`,而`getFields`返回的是*not*必须赋值给`List <String>`(如果我们忽略`String`是'最终'). (2认同)
  • @KonradRudolph是的,但值得注意的是`List <?extends X>`仍然保证所有包含的对象都可以赋值给`X`,但不允许插入`X`类型的新对象,因为它们可能与列表的实际类型不兼容.如果你可以排除插入,你可以进行赋值,即如果你有一个`A <?> a;`,你可以使用`List <String> list = Collections.unmodifiableList(a.getFields());`,as包装器可以防止您插入不兼容的元素. (2认同)