⭐⭐⭐ Spring Boot 项目实战 ⭐⭐⭐ Spring Cloud 项目实战
《Dubbo 实现原理与源码解析 —— 精品合集》 《Netty 实现原理与源码解析 —— 精品合集》
《Spring 实现原理与源码解析 —— 精品合集》 《MyBatis 实现原理与源码解析 —— 精品合集》
《Spring MVC 实现原理与源码解析 —— 精品合集》 《数据库实体设计合集》
《Spring Boot 实现原理与源码解析 —— 精品合集》 《Java 面试题 + Java 学习指南》

摘要: 原创出处 juejin.cn/post/7337147602851446810 「奔跑的毛球」欢迎转载,保留摘要,谢谢!


🙂🙂🙂关注微信公众号:【芋道源码】有福利:

  1. RocketMQ / MyCAT / Sharding-JDBC 所有源码分析文章列表
  2. RocketMQ / MyCAT / Sharding-JDBC 中文注释源码 GitHub 地址
  3. 您对于源码的疑问每条留言都将得到认真回复。甚至不知道如何读源码也可以请教噢。
  4. 新的源码解析文章实时收到通知。每周更新一篇左右。
  5. 认真的源码交流微信群。

Arrays.asList() 方法我们平时开发中一定经常使用,它是将数组转换为List的一种便捷方式,但它有一些潜在的陷阱需要注意。使用的时候需要多多注意呦。

1.不可变性

Arrays.asList() 返回的List是固定大小的,这意味着它不支持对元素的增删操作。任何试图修改大小的操作都会导致UnsupportedOperationException。

因为它返回的是 java.util.Arrays.ArrayList 的实例,而不是 java.util.ArrayList。Arrays.ArrayList 是一个内部类,它基于一个固定大小的数组,并将其包装为 List 接口的实现。因此,它不支持添加或删除元素,只能对现有元素进行修改。

源码贴张图吧,能看到size属性是按照入参的长度给定的:

示例

import java.util.Arrays;
import java.util.List;

public class Main {
public static void main(String[] args) {
// 创建一个固定大小的List
List<String> list = Arrays.asList("a", "b", "c");

// 尝试添加元素
// list.add("d"); // 这会抛出 UnsupportedOperationException

// 尝试删除元素
// list.remove(0); // 这会抛出 UnsupportedOperationException

// 尝试清空列表
// list.clear(); // 这会抛出 UnsupportedOperationException

// 可以修改现有元素
list.set(0, "A");

System.out.println(list); // 输出 [A, b, c]
}
}

2.返回的是java.util.Arrays$ArrayList

返回的列表是 java.util.Arrays 的一个私有静态类,而不是标准的 ArrayList 类。这意味着一些 ArrayList 的方法和特性可能不可用。

Arrays.asList() 返回的 ArrayList 和真正的 ArrayList 在某些方面是相似的,但也有一些重要的区别。

相似之处:

  1. 「元素访问」:两者都支持通过索引访问元素。
  2. 「迭代」:可以使用迭代器或增强型 for 循环来遍历它们。
  3. 「尺寸」:都具有 size() 方法来获取列表的大小。

区别:

1.可修改性:

  • Arrays.asList() 返回的列表是固定大小的,不能添加或删除元素,也不能调整大小。
  • 真正的 ArrayList 具有添加、删除和调整大小的方法,因此它是可修改的。

2.添加/删除元素方法:

  • Arrays.asList() 返回的列表不支持添加或删除元素的方法(例如 add()、remove() 等),尝试调用这些方法将会抛出 UnsupportedOperationException 异常。
  • 真正的 ArrayList 具有添加、删除和替换元素的方法。

3.修改元素:

  • Arrays.asList() 返回的列表允许修改元素,但不允许改变列表的大小。
  • 真正的 ArrayList 则允许修改元素,并且也可以添加或删除元素。

4.toArray() 方法:

  • Arrays.asList() 返回的列表的 toArray() 方法返回的数组是底层数组的视图,对该数组的修改将反映在列表中。
  • 真正的 ArrayList 的 toArray() 方法则返回一个全新的数组副本,对该数组的修改不会影响到列表。

5.clear() 方法:

  • 真正的 ArrayList 有一个 clear() 方法,用于清空列表中的所有元素,而 Arrays.asList() 返回的列表不支持此方法。

3.数组元素类型必须是引用类型

Arrays.asList() 方法的参数是可变参数(varargs),并且泛型参数类型被推断为数组的类型。因此,如果传递的是基本数据类型的数组,它将被看作是一个对象,而不是数组。因为它的签名是 asList(T... a),其中 T 是泛型类型。这意味着我们可以传递零个或多个参数给这个方法,而不需要显式地创建一个数组来传递。

❝

对于参数类型的推断,Java 中的自动装箱和拆箱会影响到这一点。自动装箱是指基本数据类型可以自动转换为对应的包装类型,而自动拆箱则是指包装类型可以自动转换为基本数据类型。因此,如果传递的是基本数据类型的数组,Java 会将其自动装箱为对应的包装类型的数组。

❞

这也是为什么如果传递的是基本数据类型的数组,它将被看作是一个对象,而不是数组。这里的数组实际上是对象数组,而不是基本数据类型的数组。

示例:

int[] array = {1, 2, 3};
List<int[]> list = Arrays.asList(array); // 注意这里的泛型参数是 int[]
System.out.println(list.size()); // 输出 1,因为传递了一个对象,即整个数组作为一个元素

相反,如果传递的是包装类型的数组,它将会被识别为数组的数组元素:

Integer[] array = {1, 2, 3};
List<Integer> list = Arrays.asList(array); // 注意这里的泛型参数是 Integer
System.out.println(list.size()); // 输出 3,因为传递了三个元素,即数组的每个元素都是列表的一个元素

4.数组内容修改影响List

因为Arrays.asList() 返回的List是基于原始数组的,如果对原始数组进行修改,会影响到返回的List,反之亦然。

示例:

String[] array = {"one", "two", "three"};
List<String> list = Arrays.asList(array);
System.out.println(list);//输出 [one, two, three]
array[0] = "four";
System.out.println(list); // 输出 [four, two, three]
list.set(1, "five");
System.out.println(Arrays.toString(array)); // 输出 [four, five, three]

5.使用ArrayList构造新的可变List

如果需要一个可变的List,最好使用new ArrayList<>(Arrays.asList(array)),这样就可以避免固定大小和不可变性的问题。

示例:

String[] array = {"one", "two", "three"};
List<String> list = new ArrayList<>(Arrays.asList(array));
list.add("four"); // 不会抛出 UnsupportedOperationException

总体而言,使用Arrays.asList()时,要注意其返回的List的特性,以避免潜在的问题。在需要可变性、对List进行增删操作或处理包含null元素的数组时,建议使用new ArrayList<>(Arrays.asList(array))等方式。

文章目录
  1. 1. 1.不可变性
    1. 1.0.1. 示例
  • 2. 2.返回的是java.util.Arrays$ArrayList
    1. 2.0.1. 相似之处:
    2. 2.0.2. 区别:
  • 3. 3.数组元素类型必须是引用类型
    1. 3.0.1. 示例:
  • 4. 4.数组内容修改影响List
    1. 4.0.1. 示例:
  • 5. 5.使用ArrayList构造新的可变List
    1. 5.0.1. 示例: