Java - 一道关于Arrays.asList的题目
题目
有这样一道有趣的题目:
final int[] test = new int[]{1,2,3,4};
final Integer[] test2 = new Integer[]{1,2,3,4};
final List list1 = Arrays.asList(test);
final List list2 = Arrays.asList(test2);
final List list3 = Arrays.asList(1,2,3,4);
System.out.println(list1.size());
System.out.println(list2.size());
System.out.println(list3.size());
对于上边的3个size(),输出的结果如下:
1
4
4
这道题考察的是Arrays.asList()这个api以及泛型的知识点,工作时用到该api的情景也挺多的。下面分析下,为什么是这个答案。
分析
对于list1,为什么size是1?
这是因为Arrays.asList如果传入的数组是基础数据类型的数组时,会将整个数组作为一个对象来构建ArrayList,所以size是1。在源码实现中:
public static <T> List<T> asList(T... a) {
return new ArrayList<>(a);
}
private static class ArrayList<E> extends AbstractList<E>
implements RandomAccess, java.io.Serializable
{
private static final long serialVersionUID = -2764017481108945198L;
private final E[] a;
ArrayList(E[] array) {
a = Objects.requireNonNull(array);
}
@Override
public int size() {
return a.length;
}
……
}
可以看到,Arrays.asList的形参是可变参数T... a,等同于一个数组参数T[]。这里的T是泛型。在调用该api时,会直接用传入的参数来构建一个ArrayList。
这个ArrayList<E>是Arrays的静态内部类,同样使用了泛型,而泛型是不支持基础数据类型的。
当传入的参数是一个基础数据类型的数组时,就把整个数组对象解析为泛型T;如果传入的参数是一个对象类型的数组,就把数组中的对象类型解析为泛型T。如下:
传入的参数是int[]时:
int[] -> T[]中的T,此时Arrays.asList()返回的是一个size为1的ArrayList<int[]>
传入的参数是Integer[]时:
Integer[] -> T[],此时Arrays.asList()返回的是一个ArrayList<Integer>,其size的值与Integer[]的length一样
因此,题目里的list1和list2的size会不一样。那为什么直接传入1,2,3,4这四个int参数所得到的结果又是4呢?
这是因为当直接传入参数为基础数据类型时,由于方法形参是泛型数组,于是就通过自动装箱把基础数据类型的参数包装为对应的包装类。比如传入的是int,就自动装箱成Integer,这样就能被泛型所接收了。
也就是说,虽然传入参数是1,2,3,4,其实会通过自动装箱变成一个Integer[]参数,然后传递给T[],最后返回的就是一个ArrayList<Integer>。
下面是一个可以证明该过程的例子:
public static void main(final String[] args) {
final int[] array1 = new int[]{1,2,3,4};
final Integer[] array2 = new Integer[]{1,2,3,4};
test(array1);
test(array2);
test(1,2,3,4);
}
public static <T> void test(final T... a) {
System.out.println(a.length);
}
其结果如下:
1
4
4
Arrays.asList的其他知识点
由于Arrays.asList返回的是Arrays的静态内部类ArrayList,这个ArrayList并没有重写add和remove方法的。也就是说,这个ArrayList一旦new出来了,其大小就固定下来了,不能再调用add或者remove方法了,否则就会报错如下:
Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(AbstractList.java:148)
at java.util.AbstractList.add(AbstractList.java:108)
虽然不能调用add或者remove,但可以调用set、contains、sort等其他的方法,也可以进行遍历。
如果我们确实需要调用add或者remove方法,可以有以下方法:
方法一
遍历Arrays.asList返回的集合,然后一个个添加到我们常用的集合里,比如java.util.ArrayList。
方法二
使用list.addAll(Arrays.asList(a)),直接把Arrays.asList返回的集合给整个添加到新的集合里。
方法三
可以直接通过new ArrayList<>(Arrays.asList(a))的方法来构建一个有着完善功能的集合。
方法四
使用Collections.addAll()来替代Arrays.asList(),这样得到的就是一个有着完善功能的集合。
泛型(Generics)的知识点
泛型的定义:在程序中我们将一个对象放入集合中,但是集合不会记住对象的类型,当我们在次使用对象的时候,对象变为Object类型,而程序中还是原来的类型,我们必须要自己转换其类型,为了解决这个问题,则提出泛型。
泛型要求包容的是对象类型,而八种基础数据类型不属于对象类型,但是它们有对应的封装类/包装类。并且在调用函数时,会根据参数类型来进行自动装箱或者自动拆箱(Autoboxing and unboxing)。对自动装箱/拆箱有兴趣的可以参考下边的链接。
参考链接
Java - 一道关于Arrays.asList的题目的更多相关文章
- Java中关于Arrays.asList()的操作
我们可以通过Arrays.asList() 产生一个List,但是要记住,我们通过Arrays.asList产生的list是基于一个固定大小的数组的, 仅支持那些不会改变数组大小的操作.所以我们在使用 ...
- Java中关于Arrays.asList方法的深入学习与理解
Java的标准库中在java.util包下提供了很多实用的工具类,如:Arrays,Collections等工具类都提供了一些比较实用的方法.在实际的开发使用中,我们经常需要使用这样的需求:将一个数组 ...
- 为什么Java里的Arrays.asList不能用add和remove方法?
在平时的开发过程中,我们知道能够将一个Array的对象转化为List.这种操作,我们仅仅要採用Arrays.asList这种方法即可了.笔者前段时间一直用这种方法,有一天,我发现通过Arrays.as ...
- 【Java 基础】Arrays.asList、ArrayList的subList注意事项
1. 使用Arrays.asList的注意事项 1.1 可能会踩的坑 先来看下Arrays.asList的使用: List<Integer> statusList = Arrays.asL ...
- Arrays.asList 为什么不能 add 或者 remove 而 ArrayList 可以
分析如下例子: 1 import java.util.Arrays; 2 import java.util.List; 3 4 5 public class Test { 6 public stati ...
- 关于 ArrayList.toArray() 和 Arrays.asList().toArray()方法
1.ArrayList.toArray() 理解 * 通过源码我们可以看到返回的是Object类型的数组,失去了原有的实际类型,虽然底层存储是具体类型的对象,这也正体现了文档中说的:该方法起到了 ...
- Arrays.asList()使用指南
简介 Arrays.asList()在平时开发中还是比较常见的,我们可以使用它将一个数组转换为一个List集合. String[] myArray = { "Apple", &qu ...
- 【转】java.util.Arrays.asList 的用法
DK 1.4对java.util.Arrays.asList的定义,函数参数是Object[].所以,在1.4中asList()并不支持基本类型的数组作参数. JDK 1.5中,java.util.A ...
- java Arrays.asList()和Collections.addAll()
java中的方法Arrays.asList(arg1,arg2,arg3...),经常用在将多个元素或数组转化为List中的元素,但是在使用的时候,应该注意: arg1决定返回list的元素类型(即第 ...
随机推荐
- 分享知识-快乐自己:论 Mybatis中的关联关系(一对多,多对一,多对多)
论:一对多:(举例一个省有多个市)就是实体类中有(市)类型集合属性:多对一:(多个市有一个共同的省)就是类中有(省)类型的属性.下面来介绍:一对一.多对一的使用方式. 一对多方: package ml ...
- 分享知识-快乐自己:Hibernate框架常用API详解
1):Configuration配置对象 Configuration用于加载配置文件. 1): 调用configure()方法,加载src下的hibernate.cfg.xml文件 Configura ...
- Git_学习_02_ 分支
Git鼓励大量使用分支: 1.查看分支:git branch 2.创建分支:git branch <name> 3.切换分支:git checkout <name> 4.创建+ ...
- python读文件出现中文乱码
更新: 一个解释更详细和全面的博文:https://www.cnblogs.com/zhangqigao/p/6496172.html 最近开始处理中文文本,读取文件有时候会出现乱码.原因:编码和解码 ...
- 《java编程思想》:第五章,初始化与清理
知识点整理: 1.从概念上讲,‘初始化’与‘创建’是彼此独立的,但是在Java中,两者被捆绑在一起,不可分离. 2.区分重载的方法:每个重载的方法都有一个独一无二的参数类型列表. 甚至参数顺序的不同也 ...
- 善用搜索--->描述问题 [关于SwipeRefreshLayout]
遇到了一个问题,SwipeRefreshLayout没法在加载listView之前呈现progressBar.我一直在想,是不是只能在listView加载出来才能呈现它. 发邮件问了一个开发者,他说他 ...
- 作业3rd
第三周作业 课本学习 使用nmap扫描特定靶机 使用nessus扫描特定靶机 靶机网络情况如下 在攻击机使用Nessus,步骤如下 新建一个扫描 填入目的主机ip,点击开始进行扫描 等待 扫描结果如下 ...
- ACM学习历程—HDU1028 Ignatius and the Princess(组合数学)
Ignatius and the Princess Description "Well, it seems the first problem is too easy. I w ...
- 洛谷P3252 [JLOI2012]树
题目描述 在这个问题中,给定一个值S和一棵树.在树的每个节点有一个正整数,问有多少条路径的节点总和达到S.路径中节点的深度必须是升序的.假设节点1是根节点,根的深度是0,它的儿子节点的深度为1.路径不 ...
- 描述怎样通过flask+redis+sqlalchemy等工具,开发restful api
flask开发restful api系列(8)-再谈项目结构 摘要: 进一步介绍flask的项目结构,使整个项目结构一目了然.阅读全文 posted @ 2016-06-06 13:54 月儿弯弯02 ...