Java Arrays.asList()方法详解

Java Arrays.asList()方法详解本文是对 Arrays asList 方法从源码角度进行分析 解析使用中的一些困惑 首先看 Arrays asList 的源码 publicstatic T a returnnewArr a 使用该方法可以将一个变长参数或者数组转换成 List 看似很简单但实际使用起来却会发现存在很多问题 看下面代码来发现问题

本文是对Arrays.asList()方法从源码角度进行分析,解析使用中的一些困惑。

首先看Arrays.asList()的源码

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

使用该方法
可以将一个变长参数或者数组转换成List

看似很简单但实际使用起来却会发现存在很多问题,看下面代码来发现问题。

先来看第一个问题,基本类型数组作为参数问题。

public class ArraysAsListTest { public static void main(String[] args) { int[] a = {1,2,3}; Integer[] b = {1,2,3}; List listA = Arrays.asList(a); List listA1 = Arrays.asList(1,2,3); List listB = Arrays.asList(b); System.out.println(listA.size());//out:1 System.out.println(listA1.size());//out:3 System.out.println(listB.size());//out:3 } }

嗯?用int类型的数组作为参数为什么输出size是1呢,使用Integer类型size就是3了呢。

再看源码,asList接收的是一个泛型变长参数,而我们知道基本类型是不能泛型化的,就是说8种基本类型不能作为泛型参数,要想作为泛型参数就要使用其所对应的包装类。

但是listA的Size为什么是1呢,这是因为listA传递的是一个int类型的数组,数组是一个对象,它是可以泛型化的,也就是说例子中是把一个int类型的数组作为了T的类型,所以转换后在List中就只有一个类型为int数组的元素。后边ListA1与ListB也就可以理解了,一个是进行了自动打包,一个是本来就是包装类型。

我们可以打印下list中元素类型进行验证

 System.out.println("ListA元素类型:"+listA.get(0).getClass()); //out:ListA元素类型:class [I
 System.out.println("ListA元素:"+Arrays.toString((int[]) listA.get(0)));  //ListA元素:[1, 2, 3] 该处是为了验证list中元素 System.out.println("ListA1元素类型:"+listA1.get(0).getClass()); //out:ListA1元素类型:class java.lang.Integer System.out.println("ListB元素类型:"+listB.get(0).getClass()); //out:ListB元素类型:class java.lang.Integer

接下来看第二个问题asList()方法返回对象使用add()方法抛出异常,还是先看代码

public class ArraysAsListTest { public static void main(String[] args) { List 
   
     pets = Arrays.asList("cat","dog"); pets.add("what"); } } 
   
异常:
Exception in thread "main" java.lang.UnsupportedOperationException at java.util.AbstractList.add(Unknown Source) at java.util.AbstractList.add(Unknown Source) at ArraysAsListTest.main(ArraysAsListTest.java:9)



What?一个List执行add方法会抛出异常,难道add方法不是List的基本用法吗。还是来研究下asList的实现吧

查看一下Arrays.asList中使用的ArrayList到底长啥样?

原来Arrays的asList方法使用的ArrayList类是一个内部定义的类,而不是java.util.ArrayList类。看其部分源码

public class Arrays { ....... private static class ArrayList 
     
       extends AbstractList 
      
        implements RandomAccess, java.io.Serializable { private static final long serialVersionUID = -0L; private final E[] a; ArrayList(E[] array) { if (array==null) throw new NullPointerException(); a = array; } ...... } } 
       
     


这个静态内部类,存储数组元素的a变量是final类型的,由此判断,这个静态内部类是不能做任何内部元素的添加删除操作的!就跟String类一样,String对象存储字符数组的变量也是有final修饰符的。因为一旦增加数组元素,这个数组容量已经定好的容器就无法装载增加的元素了。

内部类里面并没有add,remove方法,可以看下这个类继承的AbstractList类里面对这些方法的实现

public abstract class AbstractList 
     
       extends AbstractCollection 
      
        implements List 
       
         { ........ public void add(int index, E element) { 
         throw new UnsupportedOperationException(); } public E remove(int index) { 
         throw new UnsupportedOperationException(); } } 
        
       
     

Ok!找到异常的来源了,我们使用asList得到的对象add、remove方法直接就是抛出异常

如果要对asList得到的对象使用add、remove方法可以使用如下解决办法

List 
     
       pets = new ArrayList 
      
        (Arrays.asList("a", "b", "c")); 
       
     

那么再来看最后一个问题,上代码

public class ArraysAsListTest { public static void main(String[] args) { String[] test = {"a","b","c","d","e"}; List 
     
       testList = Arrays.asList(test); System.out.println("list原始顺序:"+testList); //洗牌打乱list中元素顺序 使用Collections.shuffled方法 Collections.shuffle(testList, new Random(2)); System.out.println("list打乱后顺序:"+testList); //list顺序打乱后 原数组会发生神马??? System.out.println("list打乱顺序后数组内容:"+Arrays.toString(test)); /* * list原始顺序:[a, b, c, d, e] list打乱后顺序:[e, a, c, b, d] list打乱顺序后数组内容:[e, a, c, b, d] */ } } 
     

哦,NO!!!我只是改变list的顺序,然而数组顺序却也发生了变化,很多时候这并不是我们想要的。

这时候我们就要意识到Arrays.asList()产生的list对象会使用底层数组作为其物理实现,只要执行操作修改这个list就会修改原来的数组。要想不改变原来数组,就要在另一个容器中创建一个副本,写法如下

List 
     
       testList = new ArrayList 
      
        (Arrays.asList(test)); 
       
     





















版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/216030.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月18日 下午12:43
下一篇 2026年3月18日 下午12:44


相关推荐

  • Spring的静态代理与动态代理[通俗易懂]

    Spring的静态代理与动态代理[通俗易懂]简述AOP是可以横向扩展功能的,能够在不修改原来代码的前提下实现功能扩展,AOP的实现原理即是动态代理+反射。为什么要使用代理1.什么是代理  代理即是将被代理对象进一步封装后,隐藏被代理对象,在不修改被代理对象代码的前提下完成一些额外的处理。2.场景描述  有一个BookService类,其中有一个add方法,现在想在执行hello方法之前打印一句话,例如是打印”…

    2022年10月17日
    3
  • 30 个 Python 编程实用技巧

    30 个 Python 编程实用技巧作者主页 海拥作者简介 CSDN 全栈领域优质创作者 HDZ 核心组成员 蝉联 C 站周榜前十粉丝福利 粉丝群每周送四本书 每月送各种小礼品 搪瓷杯 抱枕 鼠标垫 马克杯等 直接跳到末尾去评论区领书今天 我给大家带来了一些基本的 Python 编程技巧 所有这些技巧都可以帮助您减少代码并优化执行 你可以在处理常规任务时轻松地在实时项目中使用它们 目录 1 就地交换两个数字 2 比较运算符的链接 3 使用三元运算符进行条件赋值 4 使用多行字符串

    2026年3月16日
    47
  • 浅析GPU通信技术(中)-NVLink总线协议

    浅析GPU通信技术(中)-NVLink总线协议1 背景 上一篇文章 浅析 GPU 通信技术 上 GPUDirectP2P 中我们提到通过 GPUDirectP2P 技术可以大大提升 GPU 服务器单机的 GPU 通信性能 但是受限于 PCIExpresss 总线协议以及拓扑结构的一些限制 无法做到更高的带宽 为了解决这个问题 NVIDIA 提出了 NVLink 总线协议 本篇文章我们就来谈谈 NVIDIA

    2026年3月17日
    4
  • python lambda表达式_Python进阶

    python lambda表达式_Python进阶Lambda表达式lambda表示的是匿名函数,不需要用def来声明,一句话就可以声明出一个函数语法函数名=lambda参数:返回值注意点1.函数的参数可以有多个,多个参数之间用逗号隔

    2022年7月31日
    10
  • vue中mousewheel滚动

    vue中mousewheel滚动效果点击上下可以中间滚动 鼠标在框内滚动也会滚动 外部 jsconstmouse wheel opt console log opt if opt target console log 什么都没有 还让我帮忙 return

    2026年1月22日
    3
  • 蓝墨云班课资源下载不了_蓝墨云班课老师怎么用

    蓝墨云班课资源下载不了_蓝墨云班课老师怎么用看见有人详细讲解了下载文件的原理,在这里我就不赘述了,直接上写好的代码。可能乱了点。有一点要提前说一下,做这个的时候,我想着只下载没有获得经验的文件。已经获得过经验的文件因为我用不到,所以就不用下,当然,改一下代码的话没货的经验的也能下。相关的代码在download_sours函数里面,jy表示的是经验,jy=N代表没获得经验的文件,改一下就行,去掉这个判断条件就能下载已经获得经验的资源了。最后,封装好的软件下载链接在文章最末尾importosimportreimporttimeimpor

    2025年6月25日
    7

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号