欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页

asList 引发的血案

程序员文章站 2022-06-08 08:24:46
...

详情见如下代码:


  @Test
  public void testArraysList(){
      Integer[] a = {1,2,3,4,5};
      List<Integer> list = Arrays.asList(a);

      //尝试着向集合中再添加一个元素。
      list.add(6);

      for( Integer temp : list ) {
          System.out.println(temp);
      }
  }

  很简单的程序啊,不过,这段程序执行会不会有什么问题呢?

  运行后,会出现如下结果:


java.lang.UnsupportedOperationException
    at java.util.AbstractList.add(AbstractList.java:148)
    at java.util.AbstractList.add(AbstractList.java:108)

  UnsupportedOperationException,不支持的操作。居然不支持 List 的 add 方法,真是奇怪了!还是追根寻源,看看 asList 的源码:


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

  直接 new 了一个 ArrayList ,难道 ArrayList 不支持 add 方法?不可能呀!问题就出在这个 ArrayList 上,此处的 ArrayList 并非我们熟悉的 java.util.ArrayList,而是 ArrayList 工具类中的一个内置类。

asList 引发的血案


    //这是一个私有的静态内部类
    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);
        }

        /*其他方法省略*/

    }

  这里的 ArrayList 是一个静态私有内部类,除了 Arrays 能访问外,其他类度不能访问。仔细看这个类,发现它没有提供 add 方法,那肯定是父类 AbstractList 提供的,来看代码:

    public boolean add(E e) {
        add(size(), e);
        return true;
    }
    public void add(int index, E element) {
        throw new UnsupportedOperationException();
    }

  父类确实提了 add 方法,但是没有具体的实现,所以每个子类都要覆写 add 方法,而 ArrayList 没有覆写,因此 add 一个元素就会报错。

  
通过源码发现,ArrayList 静态内部类,它实现了如下一些常用方法: 

  • size:元素数量
  • toArray:转换为一个数组
  • get:获得指定元素
  • set:重置指定元素
  • indexOf:返回指定元素的索引下标
  • contains:是否包含某元素
  • sort:排序

      对于我们经常使用的 List.add 和 List.remove() 方法,都没有实现,也就是说, asList 返回的是一个长度不可变的列表,数组是多长,转换的列表也就是多长,不再保持列表动态边长的特性。
      

      虽然 Arrays.asList 用起便捷,但是却深藏着重大隐患 —— 列表长度无法修改切记千万不要把这样的 List 对象传递到一个允许 add 操作的方法中

相关标签: asList