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)。对自动装箱/拆箱有兴趣的可以参考下边的链接。

参考链接

原文地址:https://www.cnblogs.com/yulinlewis/p/10801073.html

时间: 2024-12-16 19:51:16

Java - 一道关于Arrays.asList的题目的相关文章

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

在平时的开发过程中,我们知道可以将一个Array的对象转化为List.这样的操作,我们只要采用Arrays.asList这个方法就行了.笔者前段时间一直用这个方法,有一天,我发现通过Arrays.asList得到的List无法进行add和remove等操作. 下面是一段很简单的测试代码: public class MainFacade { public static void main(String[] args) { List<Integer> list = Arrays.asList(1,

java神坑系列——Arrays.asList

java神坑系列--第二版 Arrays.asList 数组转list是java程序员经常要用的一个方法,但是这也有一个大坑------上题 这个输出什么 ,很多人期待是[1, 2, 3,4]  .但是 但是并不是.而报编译错误. 掉坑里了吧!看源码 感觉没错呀!可是此ArrayList非彼ArrayList ,    java.util.Arrays.ArrayList.ArrayList 它是array类的一个内部类!掉坑里了吧!哈哈 ing 坑主你好! 如果想用数组转list还要添加数据的

Java中使用Arrays.asList初始化ArrayList

package xiaoling; import java.util.Arrays; import java.util.ArrayList; import java.util.List; public class ListTest{ public static void main(String[] args){ List<List<Integer>> list = new ArrayList<>(); for (int num=0; num<10; ++num){

Arrays.asList()方法

// Collection<Integer> integers = new ArrayList<Integer>();//(Arrays.asList(1,2,3,4,5)); Collection<Integer> integers = new ArrayList<Integer>(Arrays.asList(1,2,3,4,5));// integers = Arrays.asList(1,2,3,4,5); System.out.println(int

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

分析如下例子: 1 import java.util.Arrays; 2 import java.util.List; 3 4 5 public class Test { 6 public static void main(String[] args) { 7 Integer[] a = {0,1,2,3,4,5,6}; 8 List<Integer> c = Arrays.asList(a); 9 for (Integer integer : c) { 10 System.out.print

【Java基础】一个有意思的泛型方法Arrays.asList(T... a)

总结 利用Arrays.asList方法返回的List是不允许add和remove的,这种list的长度不可变,因为底层依然是写数组. Arrays.asList的返回值是调用是传入T类型的List,所以传入啥,返回啥的列表 T... a 底层本来就是转换为T[] x的数组,所以如果传入的T是数组,最后的底层参数是二维数组T[][] y. Arrays.asList(T... a)方法的作用 将数组转为集合的方法,返回的是List集合.和Collection的toArray对应,是数组和集合间相

java Arrays.asList的用法

import java.util.Arrays; import java.util.List; /** * * 本类演示了Arrays类中的asList方法 * 通过四个段落来演示,体现出了该方法的相关特性. * * (1) 该方法对于基本数据类型的数组支持并不好,当数组是基本数据类型时不建议使用 * (2) 当使用asList()方法时,数组就和列表链接在一起了. *     当更新其中之一时,另一个将自动获得更新. *     注意:仅仅针对对象数组类型,基本数据类型数组不具备该特性 * (

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

DK 1.4对java.util.Arrays.asList的定义,函数参数是Object[].所以,在1.4中asList()并不支持基本类型的数组作参数. JDK 1.5中,java.util.Arrays.asList的定义,函数参数是Varargs, 采用了泛型实现.同时由于autoboxing的支持,使得可以支持对象数组以及基本类型数组. 不过在使用时,当传入基本数据类型的数组时,会出现小问题,会把传入的数组整个当作返回的List中的第一个元素,例如: public static vo

java使用Arrays.asList快速创建List集合

程序中某段案例代码如下: Map<String, List<CronTrigger>> tMap = new HashMap<String, List<CronTrigger>>(); tMap.put(name, Arrays.asList(new CronTrigger[] { trigger })); 程序运行抛出异常:java.lang.UnsupportedOperationException 错误原因: 为了快速创建List而使用了Arrays.