Java-Arrays.asList()使用中的问题

本文揭示了使用 Java 中 Arrays.asList 方法的两个常见误区:一是使用基本数据类型数组转换为 List 导致的单元素列表问题;二是 asList 生成的列表不可变,尝试增删元素会抛出 UnsupportedOperationException 异常。

转载http://wiki.jikexueyuan.com/project/java-enhancement/java-thirtysix.html
在实际开发过程中我们经常使用 asList 讲数组转换为 List,这个方法使用起来非常方便,但是 asList 方法存在几个缺陷:
一、避免使用基本数据类型数组转换为列表
使用 8 个基本类型数组转换为列表时会存在一个比较有味的缺陷。先看如下程序:

public static void main(String[] args) {
        int[] ints = {1,2,3,4,5};
        List list = Arrays.asList(ints);
        System.out.println("list'size:" + list.size());
    }
    ------------------------------------
    outPut:
    list'size:1

程序的运行结果并没有像我们预期的那样是 5 而是逆天的 1,这是什么情况?先看源码:

public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

asList 接受的参数是一个泛型的变长参数,我们知道基本数据类型是无法发型化的,也就是说 8 个基本类型是无法作为 asList 的参数的, 要想作为泛型参数就必须使用其所对应的包装类型。但是这个这个实例中为什么没有出错呢?因为该实例是将 int 类型的数组当做其参数,而在 Java 中数组是一个对象,它是可以泛型化的。所以该例子是不会产生错误的。既然例子是将整个 int 类型的数组当做泛型参数,那么经过 asList 转换就只有一个 int 的列表了。如下:

public static void main(String[] args) {
    int[] ints = {1,2,3,4,5};
    List list = Arrays.asList(ints);
    System.out.println("list 的类型:" + list.get(0).getClass());
    System.out.println("list.get(0) == ints:" + list.get(0).equals(ints));
}
--------------------------------------------
outPut:
list 的类型:class [I
list.get(0) == ints:true

从这个运行结果我们可以充分证明 list 里面的元素就是 int 数组。弄清楚这点了,那么修改方法也就一目了然了:将 int 改变为 Integer。

public static void main(String[] args) {
        Integer[] ints = {1,2,3,4,5};
        List list = Arrays.asList(ints);
        System.out.println("list'size:" + list.size());
        System.out.println("list.get(0) 的类型:" +  list.get(0).getClass());
        System.out.println("list.get(0) == ints[0]:" + list.get(0).equals(ints[0]));
    }
    ----------------------------------------
    outPut:
    list'size:5
    list.get(0) 的类型:class java.lang.Integer
    list.get(0) == ints[0]:true

Java 细节(2.1):在使用 asList 时不要将基本数据类型当做参数。
二、asList 产生的列表不可操作
对于上面的实例我们再做一个小小的修改:

public static void main(String[] args) {
        Integer[] ints = {1,2,3,4,5};
        List list = Arrays.asList(ints);
        list.add(6);
    }

该实例就是讲 ints 通过 asList 转换为 list 类别,然后再通过 add 方法加一个元素,这个实例简单的不能再简单了,但是运行结果呢?打出我们所料:

Exception in thread "main" java.lang.UnsupportedOperationException
    at java.util.AbstractList.add(Unknown Source)
    at java.util.AbstractList.add(Unknown Source)
    at com.chenssy.test.arrayList.AsListTest.main(AsListTest.java:10)

运行结果尽然抛出 UnsupportedOperationException 异常,该异常表示 list 不支持 add 方法。这就让我们郁闷了,list 怎么可能不支持 add 方法呢?难道 JDK 脑袋堵塞了?我们再看 asList 的源码:

public static <T> List<T> asList(T... a) {
        return new ArrayList<>(a);
    }

asList 接受参数后,直接 new 一个 ArrayList,到这里看应该是没有错误的啊?别急,再往下看:

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) {
            if (array==null)
                throw new NullPointerException();
            a = array;
        }
        //.................
    }

这是 ArrayList 的源码,从这里我们可以看出,此 ArrayList 不是 java.util.ArrayList,他是 Arrays 的内部类。该内部类提供了 size、toArray、get、set、indexOf、contains 方法,而像 add、remove 等改变 list 结果的方法从 AbstractList 父类继承过来,同时这些方法也比较奇葩,它直接抛出 UnsupportedOperationException 异常:

public boolean add(E e) {
        add(size(), e);
        return true;
    }

    public E set(int index, E element) {
        throw new UnsupportedOperationException();
    }

    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }

    public E remove(int index) {
        throw new UnsupportedOperationException();
    }

通过这些代码可以看出 asList 返回的列表只不过是一个披着 list 的外衣,它并没有 list 的基本特性(变长)。该 list 是一个长度不可变的列表,传入参数的数组有多长,其返回的列表就只能是多长。所以:

<think>我们被要求回答关于JavaArrays.asList方法的使用方法和示例。根据提供的引用,我们可以总结如下: Arrays.asList()java.util.Arrays类的一个静态方法,用于将数组或指定的一组对象换为一个List集合。但需要注意的是,这个List是一个固定大小的列表,由原始数组支持,因此不能进行添加或删除等改变大小的操作,否则会抛出UnsupportedOperationException异常。 ### 主要特性: 1. **固定大小**:返回的列表是基于原始数组的,因此长度固定,不能添加或删除元素。 2. **视图**:返回的列表是数组的一个视图,对列表的修改(如set方法)会反映到原数组上,反之亦然。 3. **不支持基本类型数组**:如果传入一个基本数据类型(如int[])的数组,整个数组会被视为一个元素,因为泛型T不能是基本类型。 ### 使用方法: ```java import java.util.Arrays; import java.util.List; public class Main { public static void main(String[] args) { // 示例1:将多个元素换为列表 List<String> list1 = Arrays.asList("A", "B", "C"); System.out.println(list1); // 输出: [A, B, C] // 示例2:将数组换为列表 String[] array = {"Apple", "Banana", "Orange"}; List<String> list2 = Arrays.asList(array); System.out.println(list2); // 输出: [Apple, Banana, Orange] // 修改列表会反映到原数组 list2.set(0, "Cherry"); System.out.println("修改后列表: " + list2); // 修改后列表: [Cherry, Banana, Orange] System.out.println("原数组: " + Arrays.toString(array)); // 原数组: [Cherry, Banana, Orange] // 尝试添加元素(会抛出异常) try { list2.add("Grape"); // 抛出UnsupportedOperationException } catch (Exception e) { System.out.println("不支持添加操作: " + e); } } } ``` ### 注意事项: 1. **基本类型数组问题**: ```java int[] intArray = {1, 2, 3}; List<int[]> list = Arrays.asList(intArray); // 注意:这里List的元素类型是int[],而不是Integer System.out.println(list.size()); // 输出1,因为整个intArray被当作一个元素 ``` 解决方法:使用包装类型数组 ```java Integer[] integerArray = {1, 2, 3}; List<Integer> integerList = Arrays.asList(integerArray); System.out.println(integerList.size()); // 输出3 ``` 2. **固定大小**:返回的列表不支持`add()`、`remove()`、`clear()`等改变大小的操作。 3. **序列化**:如果原数组是可序列化的,那么返回的列表也是可序列化的。 ### 应用场景: - 快速创建固定大小的列表(只读或修改元素值,不改变大小) - 需要将数组作为集合来使用(如使用集合的迭代器、contains等方法) ### 总结: `Arrays.asList()`是一个方便的工具,但使用时需注意其限制。如果需要可变列表,可以这样处理: ```java List<String> newList = new ArrayList<>(Arrays.asList(array)); ``` §§相关问题§§ 1. 如何将基本类型数组(如int[])正确换为List? 2. 为什么Arrays.asList返回的列表不支持添加和删除操作? 3. 如何创建一个可变的Arrays.asList列表? 4. Arrays.asList和Collections.singletonList有什么区别? 5.Java 8中,Arrays.asList和Stream API如何结合使用?</think>### Java `Arrays.asList()` 方法详解 `Arrays.asList()` 是 `java.util.Arrays` 类提供的静态方法,用于将数组换为固定大小的列表。以下是其核心特性和使用方法: #### 一、基本语法 ```java public static <T> List<T> asList(T... a) ``` #### 二、核心特性 1. **固定大小列表** - 返回的列表长度固定,**不能添加或删除元素** ```java List<String> list = Arrays.asList("A", "B", "C"); list.add("D"); // 抛出 UnsupportedOperationException ``` 2. **数组视图** - 列表与原始数组共享数据 ```java String[] arr = {"Apple", "Banana"}; List<String> list = Arrays.asList(arr); list.set(0, "Orange"); // 修改列表 System.out.println(arr[0]); // 输出 "Orange"(原数组同步修改) ``` 3. **不支持基本类型** - 基本类型数组会被视为单个元素 ```java int[] nums = {1, 2, 3}; List<int[]> list = Arrays.asList(nums); System.out.println(list.size()); // 输出 1(而非3) ``` #### 三、正确使用示例 ```java // 1. 字符串数组换 String[] fruits = {"Apple", "Banana", "Orange"}; List<String> fruitList = Arrays.asList(fruits); // 2. 直接传入元素 List<Integer> numbers = Arrays.asList(1, 2, 3, 4, 5); // 3. 修改元素(允许) fruitList.set(0, "Mango"); // 成功修改 // 4. 基本类型解决方案(Java 8+) int[] nums = {1, 2, 3}; List<Integer> numList = Arrays.stream(nums).boxed().collect(Collectors.toList()); ``` #### 四、常见问题及解决方案 | **问题场景** | **错误示例** | **解决方案** | |------------|------------|------------| | 添加/删除元素 | `list.add("X")` | 创建新列表:<br>`new ArrayList<>(Arrays.asList(...))` | | 基本类型处理 | `Arrays.asList(new int[]{1,2})` | 使用包装类:<br>`Arrays.asList(1, 2)` | | 修改列表大小 | `list.remove(0)` | 换为可变列表:<br>`Collections.unmodifiableList()` | #### 五、典型应用场景 1. **快速初始化只读集合** ```java List<String> colors = Arrays.asList("Red", "Green", "Blue"); ``` 2. **配合集合方法使用** ```java Collections.sort(Arrays.asList(3, 1, 4, 2)); ``` 3. **批量操作元素** ```java Arrays.asList("A","B","C").replaceAll(String::toLowerCase); ``` > **重要提示**: > 返回的 `List` 是 `Arrays` 的内部类 `ArrayList`(非标准 `java.util.ArrayList`),其底层实现基于数组,因此具有固定大小特性[^3][^4]。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值