Array 和 List 的转换问题
Array 和 List 都是我们在开发过程中常见的数据结构。我们都知道 Array 是定长的,List 是可变长。而且,List 的实现类 ArrayList 也是根据 Array 去实现的。
以下 Array 指代数组,List 指代数组列表。
Array 转 List
当然最原始的方法就是使用遍历的方式,将 Array 中的元素都添加到 List 中。这种实现方式这里不作赘述。
Java1.2 之后,Jdk 语言提供 Arrays 这个工具类。大大简化了我们常见的 Array 操作,但是也有不少需要注意的问题。
如下:
Integer[] a = { 1, 2 };
List<Integer> l = Arrays.asList(a);
这是我们常见的 Array 转换 List 的方式,但是这个使用上有一个问题。当对 List 对象 l 进行列表插入操作时:
l.add(3);
程序就会抛出异常 java.lang.UnsupportedOperationException
。这是为什么呢?
查看 Arrays.asList
源码发现,
public static <T> List<T> asList(T... a) {return new ArrayList<>(a);
}
这里返回的 ArrayList 并不是 java.util.ArrayList
而是 java.util.Arrays.ArrayList
。Arrays 又新建了一个 ArrayList 内部类,实现了一些基本 get set 方法。
回头查看 java.util.Arrays.ArrayList.ArrayList(E[] array)
构造函数,
ArrayList(E[] array) {a = Objects.requireNonNull(array);
}
不难发现,java.util.Arrays.ArrayList
虽然打着 List 的旗号,继承了 AbstractList
。但是其只是在 Array 的基础上进行了简单的封转,AbstractList
中则是直接重写了 add 方法,表示这个方法是不允许操作。
public void add(int index, E element) {throw new UnsupportedOperationException();
}
明白了这个错误产生的原因,回头想一下 Java 的这些开发者们为什么这样设计。
ArrayList 中如果要添加一个元素,则需要先对其内部的 Array 进行扩容,然后将 Old Array 复制到扩容后的 New Array 中。如果 Array 转 List 仅仅是读取操作,或是在 Array 的 Size 范围之内进行替换操作,再将 Array 复制一遍,不免会对内存进行浪费,倒不如直接将原始的 Array 直接拿来维护更为直接和高效(正如java.util.Arrays.ArrayList
的实现方式)。
明白这个缘由之后,如果要在 Array 转 List 之后,不只有只读操作,那么则需要下面的实现,
List<Integer> l = new ArrayList<>(Arrays.asList(a));
虽然在我们日常的开发过程中,已经习惯了使用 ArrayList 去代替 Array,但是了解此处 Java 的转换过程还是能够让我们少踩坑。
List 转 Array
因为 Array 的长度不可变,所以这个转换过程中,会有长度不匹配的情况。
常见的转换方法是 ArrayList.toArray()
或 ArrayList.toArray(T[])
。
这两个实现的共同点是都是对 ArrayList 中的 Array 进行 Copy 操作,生成一个新的数组返回。不同点是前者返回值是 Object[]
,后者是 T[]
。
在 ArrayList.toArray(T[])
的使用过程中需要注意,当要转换的 Array 长度小于 ArrayList 的 size 时,不要试图通过传入形参的方式进行转换,虽然这在 Array 的长度大于 List 时不会出现问题。
如下代码:
// l [1, 2, 3]
Integer[] a = new Integer[2];
l.toArray(a); // error 正确写法:a = l.toArray(a);
Stream.of(a).forEach(System.out::println);
输出结果是:null null
。
查看源码实现:
public <T> T[] toArray(T[] a) {if (a.length < size)// Make a new array of a's runtime type, but my contents:return (T[]) Arrays.copyOf(elementData, size, a.getClass());System.arraycopy(elementData, 0, a, 0, size);if (a.length > size)a[size] = null;return a;
}// Arrays.copyOf
public static <T,U> T[] copyOf(U[] original, int newLength, Class<? extends T[]> newType) {@SuppressWarnings("unchecked")T[] copy = ((Object)newType == (Object)Object[].class)? (T[]) new Object[newLength]: (T[]) Array.newInstance(newType.getComponentType(), newLength);System.arraycopy(original, 0, copy, 0,Math.min(original.length, newLength));return copy;
}
可见,当 a.length < size
成立,入参 a
并没有被使用,所以 a
依然是 new Integer[2]
。
所以,极度建议在转换之前初始化 Array 的长度为 ArrayList 的 size,并且使用返回值重新给 Array 赋值。
// l [1, 2, 3]
Integer[] b = new Integer[l.size()];
b = l.toArray(b);
Stream.of(b).forEach(System.out::println);
备注
部分内容参考:《码出高效:Java开发手册》 一书。
原文地址
Array 和 List 的转换问题相关推荐
- Java 集合 --- Array和List互相转换
Java 集合 --- Array和List互相转换 List 转 Array Array 转 List 包装类数组和基本类型数组互相转换 List 转 Array 使用toArray方法只能返回 O ...
- python中List类型与numpy.array类型的互相转换
当然要先引入numpy包 import numpy as np List转numpy.array: temp = np.array(list) numpy.array转List: arr = temp ...
- python中数组转矩阵_python实现矩阵和array数组之间的转换
python 列表.矩阵.数组之间的关系 矩阵可以实现多维切片,如: b = m[1:10, 3:20] 但是 多维列表却不可以首先,没见过b = m[1:10, 3:20] 这种写法,小编试了一下有 ...
- java array和list互相转换
打印 注:打印时不是地址而是值 System.out.println(Arrays.toString(nums)); 查看变量的数据类型 变量名.getClass().toString() list转 ...
- Python:list 和 array的对比以及转换时的注意事项
前言 array,顾名思义,数组,就是存储数字.处理数字的一种数据结构.今天在将list转换为array时,遇到了一个问题,数据量比较大,刚开始怎么都不知道问题出在哪里.直到我用一个3*3的小数据测试 ...
- Array与List的转换
1.List转为Array String[] arr = {"a","b","c"}; String[] objects = (String ...
- scala array和list互相转换
array有toList方法 list有toArray方法 非常简单,方便
- python numpy array 数组维度转换(转维)
在实践中,经常需要对中间数据或输出数据进行维度转换,保证多个数据间计算维度上的一致性. 一般主要涉及pytorch中tensorde的维度转换.numpy中array的维度转换.本篇先对array的维 ...
- Php的if自动转换类型,php之数据类型自动转换,php之数据类型转换_PHP教程
php之数据类型自动转换,php之数据类型转换 1:概述 ---php是一种弱类型的语言,它可以根据运行环境的变化而自动进行数据类型的转换 1.1转换成布尔类型的原则 以下值都将转换成布尔类型中的fa ...
最新文章
- java并发核心知识体系精讲_JAVA核心知识汇总
- linux安装apache的纠结过程
- iOS之深入解析静态库和动态库
- MySQL高级 - 常用工具 - mysqladmin
- 问题 1044: [编程入门]三个字符串的排序
- 跟一个刚毕业不久的码农聊天后被凡尔赛了
- TRUNCATE恢复-bbed
- 华科团队发布 OVIS 遮挡视频实例分割基准数据集
- 前端三大框架 Vue.js、AngularJS、React 的区别
- CSU 1115: 最短的名字(字典树)
- 《统一沟通-微软-实战》-6-部署-2-中介服务器-2-安装中介服务器
- 原型工具Axure:常用效果制作(选中、淘宝网导航、轮播图、toast效果、呼出键盘、省市二级联动、步进器、订单详情案例、中继器)
- java页面标签span_span标签跳转新页面
- 高中计算机必修选修知识点总结,高中数学必修+选修全部知识点精华归纳总结.pdf...
- 怎么设置android投屏 桌面程序,手机怎么投屏到电脑?
- 威廉•欧奈尔选股七法
- DoTween常用动画效果
- Apple推荐的2020年最佳应用程序已经出炉
- php商城开发人人分销团队级差分红升级规则订制
- 2022年金九银十软件测试面试题大全,精心挑选常问面试题
热门文章
- 区块链行业的一次“里程碑时刻”…
- HttpUnit模拟按钮点击以及爬虫实现
- C++基础编程题(06)求调和平均数(两个数,的倒数平均值的倒数)
- android聚合天气,聚合数据Android SDK 天气查询演示示例
- Java bho插件,javascript-使用IE插件浏览器帮助器对象(BHO)访...
- 三态缓存 Tri-state buffer
- Maxthon插件开发
- html怎么设置外面有线,TP-Link路由器有线方式桥接设置图文教程
- 武汉大学计算机考研分析
- 不知不觉又到了万(wu)众(liao)期(tou)待(ding)的十一黄金周了