第二十五条 列表优先于数组

数组与泛型相比,两个不同点。
1、数组是协变的,意思是如果A是B的子类型,那么数组A[]就是数组B[]的子类型;泛型则是不可变的,对于任意两个不同的类型C和D,List<C> 即不是 List<D> 的子类型,也不是基类型,不管C是不是D的子类。如果你认为泛型是有缺陷的,错了,有缺陷的是数组。


Object[] objArray = new Long[10];
objArray[0] = "I do not fit in";

这段代码是合法的,意思就是编译时不会报错,能通过编译。

List<Object> list = new ArrayList<Long>();
list.add("I do not fit in");

这段代码不合法,编译通不过,直接报错,更别说运行了。

上面两种写法,都是错误的,第一个即使编译通过了,运行起来还是会报错的,耽误工夫;第二个则直接报错。我们需要的就是尽可能早的暴露问题和错误,以便于修改。很明显,第二种占优势。

2、数组是具体化的,因此数组会在运行时检查类型,所以编译期是免检的,运行起来才发现不对劲,会抛出异常。泛型则是通过擦除来实现的,意思就是在编译期检查类型,而运行时抛弃元素类型的信息,意思是编译能通过就好了,后期一律放行,因为已经检查过了,运行时是不会出问题的。有一个例子大家可以自己写意下,就是用泛型加上反射。List<String> strs = new ArrayList<String>(); 我们可以根据反射去拿strs的add()方法,然后根据反射加入一个 Long 类型的数据,然后打印 strs的toString()方法,会发现元素添加成功。这从侧面说出运行时是没检查元素类型的,当然,此时如果用迭代器去便利元素,用String 类型接受元素,则在便利到 Long 类型数据时,会报错。可以参考下ArrayList的源码,底层是Object[] array 的数据结构。

由于以上两点,数组和泛型不能混合使用。创建泛型数组 参数化类型 类型参数的数组 是非法的,举例 new List<E>[] 、new List<String> 、 new E[] 都是不合法的,是不会编译通过的。为什么创建泛型数组会失败,是因为编译期不知道它的类型,它不是安全类型。

List<String>[] strArray = new List<String> [1];//假设允许泛型数组
        
List<Integer>[] intArray = Arrays.asList(42); // 穿件一个集合,包含一个值为 42 的元素
Object[] obj = strArray;// 多态技术,数组是协变的    
obj[0] = intList; //将intList存入了strArray中。 
String str = strArray[0].get(0); // 此时明明是个 int 类型的

通过上述例子,我们会发现,如果泛型和数组能混用,就可能会出现上面的错误,这是源码的bug,而java是比较严谨的;数组和泛型,一个是运行时检查,一个是编译时检查,通俗点就是可能会出现检查错位的情况,所用混用可能就会 出现问题,java源码直接禁止他们混用。由于泛型是不可具体化的,所以运行期间得到的信息不会比编译期间多,因为信息被擦除了,T[] 是不安全的,虚拟机根本不知道它是哪个对象,因此,对泛型使用可变参数列也是不安全的。但无限通配符居然是安全的,例如

List<?>[] stringLists=new List<?>[1]; 这种是合法的。我们知道 List<E>list = new ArrayList<>(); 是不合法的,但我们可以
List<Object> list = new ArrayList<Object>();
List<E> li = new ArrayList<E>(list);
我们可以先创建实体类,然后通过泛型技术转换。
如果我们混合数组和泛型,编译器报错了,那么,赶快使用列表代替数组。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值