Java中,集合与数组之间的相互转换

1. 集合转换为类型一致的数组

使用集合转数组的方法,必须使用集合的 toArray(T[] array)方法,传入的是类型完全一致、长度为 0 的空数组。

反例:
直接使用 toArray 无参方法存在问题,此方法返回值只能是 Object[]类,若强转其它类型数组将出现ClassCastException 错误。

List<String> list=new ArrayList<>();
list.add("aa");
list.add("bb");
list.add("cc");
// 使用无参的toArray()方法,默认的返回类型是Object []
Object[] objects = list.toArray();
        

正例:

List<String> list = new ArrayList<>(2);
list.add("guan");
list.add("bao");
String[] array = list.toArray(new String[0]);

说明:使用 toArray 带参方法,数组空间大小的 length:
1) 等于 0,动态创建与 size 相同的数组,性能最好。
2) 大于 0 但小于 size,重新创建大小等于 size 的数组,增加 GC 负担。
3) 等于 size,在高并发情况下,数组创建完成之后,size 正在变大的情况下,负面影响与 2 相同。
4) 大于 size,空间浪费,且在 size 处插入 null 值,存在 NPE 隐患

2. 数组转换为类型一致的集合

场景:现在有一个int [] arr,希望转换为一个List。

		 //  数组转换为类型一致的集合
        int [] arr1={1,2,3};
        //  注意:这里直接传入int [] 的数组,返回的List的泛型参数为 int [],而不是Integer
        List<int[]> list1 = Arrays.asList(arr1);


        Integer [] arr2={1,2,3};
        //  传入的参数类型为 Integer时,返回泛型参数就是Integer
        List<Integer> list2 = Arrays.asList(arr2);

注意:
很容易犯的一个错误就是,使用Arrays.asList()传入int [] 数组,然后用List < Integer>去接受,报错为类型不一致。

Arrays.asList的返回值:
正如上面所看到的,Arrays.asList()会返回一个List。现在我们尝试使用这个list来add(),或者remove()来操作,发现报错了。
在这里插入图片描述
看一下Arrays.asList()的源码:
在这里插入图片描述

返回了个ArrayList,但是,该ArrayList并不是java.util.ArrayList,而是Arrays的一个内部类。
在这里插入图片描述
内部ArrayList的结构:
在这里插入图片描述
可以发现它并没有重写add(),remove()两个会改变数据结构的方法,所以当我们直接使用返回的List去add或者remove时,实际上调用的是他的父类AbstractList的add/remove方法:
在这里插入图片描述
在这里插入图片描述
可以看出这里的实现就是直接抛出了一个异常!

总结:
Arrays.asList()返回的实际上是一个不允许修改其结构的List(注:set(index,val)不属于改变结构的方法)。当前希望对返回的List进行修改结构操作时,按照下面的方式即可:

		Integer [] arr2={1,2,3};
        //  传入的参数类型为 Integer时,返回泛型参数就是Integer
        List<Integer> list2 = Arrays.asList(arr2);

        //  新建一个java.util包下的List的实现类即可
        List<Integer> list=new ArrayList<>(list2);
        list.add(4);
        System.out.println(list);

注意:
看看下面的代码执行结果:

		Integer [] arr2={1,2,3};
        //  传入的参数类型为 Integer时,返回泛型参数就是Integer
        List<Integer> list2 = Arrays.asList(arr2);

        list2.set(0,111);
        System.out.println(arr2[0]);

        arr2[1]=222;
        System.out.println(list2);

在这里插入图片描述
OK,也就是说,返回的List与原数组Integer [] arr2底层使用的是同一份数据。其实前的源码已经看到了这一点:
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
可以看出,调用Arrays.asList(arr)后,new 内部的ArrayList时直接把数组arr赋值给内部变量E [] a,后面调用get()时,也是直接操作的该内部变量a。

3. 另一个“假List的情形”:

 public static void main(String[] args) {
        List<Integer> list=new ArrayList<>();
        list.add(0);
        list.add(1);
        list.add(2);
        list.add(3);
        list.add(4);

        //  取左闭右开的子List
        List<Integer> sub = list.subList(1, 3);
        System.out.println(sub);//  out:[1,2]

        sub.add(555);
        System.out.println(sub);//  out:[1,2,555]
        System.out.println(list);//  out:[0,1,2,555,3,4]

        list.add(666);
        System.out.println(list);//  out:[0,1,2,555,3,4,666]
        //  发生fast-fail异常
        System.out.println(sub);

    }

List::subList()会返回一个List:
在这里插入图片描述

这个List的实际类型是ArrayList中的一个内部类:
在这里插入图片描述
在这里插入图片描述
该类是AbstractList的子类,即也是List的实现类,它实现了add/remove方法,故我们可以调用它的add/remove方法。**但是:**它的add与remove的实现逻辑与ArrayList并不相同,从上面的测试例子以及源码描述可以可看出返回的SubList与父List共用底层的同一个存储数组,所以修改SubList的结构,父List的结构也会发生改变。

另外:

		list.add(666);
        System.out.println(list);//  out:[0,1,2,555,3,4,666]
        //  发生fast-fail异常
        System.out.println(sub);

对父List的结构修改后,当再次访问SubList时,会发生fast-fail异常。

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值