List、List<Object>、List<?>的区别

通过一个例子来比较这几种写法的区别

public class ListWithoutGeneric {
    public static void main(String[] args) {
        // 第一段:不使用泛型的方式
        List a1 = new ArrayList();
        a1.add(new Object());
        a1.add(new Integer(1));
        a1.add(new String("a1"));

        // 第二段:把a1赋值给List<Object>类型的a2,看似a2与a1没有区别
        List<Object> a2 = a1;
        a2.add(new Object());
        a2.add(new Integer(2));
        a2.add(new String("a2"));
        // 但是如果尝试把一个带有其它类型泛型的b2赋值给a2,则会编译报错
        List<String> b2 = new ArrayList<>();
        // 编译报错,这也是List与List<Object>的区别
        a2 = b2;

        // 第三段:把a1赋值给List<Integer>类型的a3,赋值过程没有编译报错,主要为了向前兼容(泛型jdk1.5之后才出现)
        List<Integer> a3 = a1;
        a3.add(new Integer(3));
        // java.lang.ClassCastException: java.lang.Object cannot be cast to java.lang.Integer
        Integer integer = a3.get(0);
        // 编译报错,不允许add非Integer类型
        a3.add(new Object());
        a3.add(new String("a3"));

        // 第四段:把a1赋值给List<?>类型的a4
        List<?> a4 = a1;
        a4.remove(0);
        a4.clear();
        a4.add(null);
        // 编译出错,不允许add非null的数据
        a4.add(new Object());
    }
}

1、第一段:定义了一个没使用泛型的List a1,向a1中添加不同类型的元素,所有功能都可以正常使用,但使用时会有类型强制转换异常的风险。

2、第二段:把a1赋值给List<Object>类型的a2,再往a2添加不同类型元素,不会编译报错,看似a2与a1没有区别,但是如果尝试把一个带有其它类型泛型(List<String>)的b2赋值给a2,则会编译报错,除非让泛型保持一致。

这也是List与List<Object>的区别:泛型之间只有同类型才能相互赋值。

3、第三段:把a1赋值给List<Integer>类型的a3,赋值过程没有编译报错,主要为了向前兼容(泛型jdk1.5之后才出现),但如果直接用Integer类型取值,会报类型转换异常。因为a3有了泛型约束,再添加其它类型元素,则会编译报错。

4、List<?>是通配符集合,一般作为参数来接收外部的集合,或者返回一个不知道具体元素类型的集合。它可以被任何类型的集合引用赋值,也可以删除元素。但是因为类型的不确定,所有不能添加非null元素(null属于任何类型)。

以上内容根据《码出高效Java开发手册》学习整理

发布了149 篇原创文章 · 获赞 100 · 访问量 18万+

猜你喜欢

转载自blog.csdn.net/u011212394/article/details/102596912