题目

有这样一道有趣的题目:

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的题目的更多相关文章

  1. Java中关于Arrays.asList()的操作

    我们可以通过Arrays.asList() 产生一个List,但是要记住,我们通过Arrays.asList产生的list是基于一个固定大小的数组的, 仅支持那些不会改变数组大小的操作.所以我们在使用 ...

  2. Java中关于Arrays.asList方法的深入学习与理解

    Java的标准库中在java.util包下提供了很多实用的工具类,如:Arrays,Collections等工具类都提供了一些比较实用的方法.在实际的开发使用中,我们经常需要使用这样的需求:将一个数组 ...

  3. 为什么Java里的Arrays.asList不能用add和remove方法?

    在平时的开发过程中,我们知道能够将一个Array的对象转化为List.这种操作,我们仅仅要採用Arrays.asList这种方法即可了.笔者前段时间一直用这种方法,有一天,我发现通过Arrays.as ...

  4. 【Java 基础】Arrays.asList、ArrayList的subList注意事项

    1. 使用Arrays.asList的注意事项 1.1 可能会踩的坑 先来看下Arrays.asList的使用: List<Integer> statusList = Arrays.asL ...

  5. Arrays.asList 为什么不能 add 或者 remove 而 ArrayList 可以

    分析如下例子: 1 import java.util.Arrays; 2 import java.util.List; 3 4 5 public class Test { 6 public stati ...

  6. 关于 ArrayList.toArray() 和 Arrays.asList().toArray()方法

    1.ArrayList.toArray() 理解    * 通过源码我们可以看到返回的是Object类型的数组,失去了原有的实际类型,虽然底层存储是具体类型的对象,这也正体现了文档中说的:该方法起到了 ...

  7. Arrays.asList()使用指南

    简介 Arrays.asList()在平时开发中还是比较常见的,我们可以使用它将一个数组转换为一个List集合. String[] myArray = { "Apple", &qu ...

  8. 【转】java.util.Arrays.asList 的用法

    DK 1.4对java.util.Arrays.asList的定义,函数参数是Object[].所以,在1.4中asList()并不支持基本类型的数组作参数. JDK 1.5中,java.util.A ...

  9. java Arrays.asList()和Collections.addAll()

    java中的方法Arrays.asList(arg1,arg2,arg3...),经常用在将多个元素或数组转化为List中的元素,但是在使用的时候,应该注意: arg1决定返回list的元素类型(即第 ...

随机推荐

  1. shell将字符串转换为大写变量并将小写作为变量值

    group_name='a b c d e f g' for a in $group_name; do typeset -u a ; echo "$a='$(echo $a | tr '[A ...

  2. React之jsx语法特性

    jsx 语法,直接可以在js中使用html标签. 还可以通过花括号的形式,在html标签中,写js表达式. <div> { 1 + 2 } hello,world! </div> ...

  3. 五年java工作应具备的技能

    具有一到五年开发经验 需要学习内容很多 JVM/分布式/高并发/性能优化/Spring MVC/Spring Boot/Spring Cloud/MyBatis/Netty源码分析等等等 01.透彻理 ...

  4. laravel基础课程---13、数据库基本操作2(lavarel数据库操作和tp对比)

    laravel基础课程---13.数据库基本操作2(lavarel数据库操作和tp对比) 一.总结 一句话总结: 非常非常接近:也是分为两大类,原生SQL 和 数据库链式操作 学习方法:使用时 多看手 ...

  5. openfire XML流

    XML流 概览 两个基本概念,XML流和XML节,使得在出席信息已知的实体之间,异步交换低负载的结构化信息成为可能.这两个术语定义如下: XML流的定义:一个XML流是一个容器,包含了两个实体之间通过 ...

  6. listen 80

    Facebook Quietly Created New Email Addresses For a company that made its name by building one of the ...

  7. codeforces 587B B. Duff in Beach(dp)

    题目链接: B. Duff in Beach time limit per test 2 seconds memory limit per test 256 megabytes input stand ...

  8. P2766 [网络流24题]最长不下降子序列问题

    ha~ «问题描述: 给定正整数序列$x_1,...,x_n$ .$n<=500$ 求(1)计算其最长不下降子序列的长度$s$. (2)计算从给定的序列中最多可取出多少个长度为$s$的不下降子序 ...

  9. 【Lintcode】136.Palindrome Partitioning

    题目: Given a string s, partition s such that every substring of the partition is a palindrome. Return ...

  10. 洛谷 2585 [ZJOI2006]三色二叉树——树形dp

    题目:https://www.luogu.org/problemnew/show/P2585 可以把不是绿色的记成一种.仔细一想不会有冲突.如果自己是绿色,孩子的不同颜色不会冲突:如果自己不是绿色,自 ...