首页 > 编程语言 >Java - 一道关于Arrays.asList的题目

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

时间:2023-02-02 11:35:38浏览次数:45  
标签:Java Arrays ArrayList 泛型 final asList size


题目

有这样一道有趣的题目:

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

参考链接

  • ​​将数组转换成集合Arrays.asList,不可进行add和remove操作的原因​​
  • ​​为什么泛型类的类型不能是基本数据类型​​
  • ​​Java 自动装箱与拆箱(Autoboxing and unboxing)​​


标签:Java,Arrays,ArrayList,泛型,final,asList,size
From: https://blog.51cto.com/u_15951177/6033416

相关文章

  • Java基础-普通类、抽象类、接口类
    普通类和抽象类的区别普通类可以有普通方法,不能有抽象方法;抽象类可以有普通方法和抽象方法普通类可以实例化,抽象类不能实例化普通类必须实现抽象类的抽象方法抽象类......
  • Java之使用zxing.jar包生成二维码
    由于时代科学的进步,二维码已经和我们的生活密不可分,在开发过程中往往会涉及到和二维码相关的开发,今天这篇文章就教会大家如何使用zxing.jar包生成二维码下面这个就是......
  • 车牌识别服务-JAVA+ONNX版本,支持全类型的车牌
    1、车牌识别简介车牌识别分为车牌检测与识别,检测模型一般需要检查车牌的位置识别模型一般为识别车牌号及车牌的颜色类型等,目前有较多的深度学习模型能支持,这里就不详细......
  • java中的自定义枚举类
    自定义枚举类有两种写法 第一种写法:classSeason{privateStringname;//在Season内部,直接创建固定的对象,//优化,可以加入final修饰符pub......
  • 基础认识-Java工具认识
    JDK——JavaDevelopmentKit扩充开发工具,父集JRE——JavaRuntimeEnvironment包含applet,保障Java语句可运行JVM——JavaVirtualMachine模拟CPU(虚拟机)解释型、编译......
  • ELK系列(4) - Elasticsearch cannot write xcontent for unknown value of type class
    问题与分析在使用Elasticsearch进行index数据时,发现报错如下:java.lang.IllegalArgumentException:cannotwritexcontentforunknownvalueoftypeclassjava.math.BigD......
  • Java Socket通信(一)之客户端程序 发送和接收数据
     JavaSocket通信(一)之客户端程序发送和接收数据网络应用分为客户端和服务端两部分,而Socket类是负责处理客户端通信的Java类。通过这个类可以连接到指定IP或域名的服务......
  • Java中Socket 实现最简单的客户端与服务端通信
    Java中Socket实现最简单的客户端与服务端通信引言:因为最近项目中要接入某通信协议接口,基于TCP/IP的socket接口。于是就在本地弄一个最简单的Socket通信仅供学习。话不多......
  • JavaScript 中URL构造函数
    前言URL对于我们开发人员来讲,应该是非常熟悉了。在对URL进行参数拼接时,我们一般都会直接进行字符串拼接或使用模版字符串,因为这样非常方便,但是我们这样其实会在不知不觉......
  • 通过IDEA生成JavaDoc文档
    一.通过IDEA来生成JavaDoc文档:1.创建一个存放JavaDoc的文件夹2.打开IDEA上方工具(Tools),生成JavaDoc文档(GenerateJavaDoc...)//如图一3.选择我们要生成的......