• JDK 之 Arrays.asList


    Arrays工具类提供了一个方法asList, 使用该方法可以将一个变长参数或者数组转换成List

    其源代码如下:

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

      

    问题发现

    根据上述方法的描述,我们先来编写几个例子:

    public class ArrayExample {
     
     public static void main(String[] args) {
      
      /**使用变长参数*/
      List<String> array1 = Arrays.asList("Welcome", "to","Java", "world");
      System.out.println(array1);
      
      /**使用数组*/
      List<String> array2 = Arrays.asList(new String[] {"Welcome", "to","Java", "world"});
      System.out.println(array2);
     }
    
    }
    

     运行上述程序,输出如下内容。

    [Welcome, to, Java, world]
    [Welcome, to, Java, world]

    心血来潮,突然想在创建的列表中添加一个字符串“Cool~~~”,  走一个。

     /**使用变长参数*/
      List<String> array1 = Arrays.asList("Welcome", "to","Java", "world");
      array1.add("Cool~~~");
    

      

    结果,遇到一个UnsupportedOperationException异常:

    Exception in thread "main" java.lang.UnsupportedOperationException
     at java.util.AbstractList.add(Unknown Source)
     at java.util.AbstractList.add(Unknown Source)
     at test.ArrayExample.main(ArrayExample.java:36)
    

      

    不可思议,new ArrayList<>(a)产生的列表调用add方法,竟然遇到问题。

    原因查找

    那么问题来了,到底发生了什么事情?带着疑问,去查看一下Arrays.asList中使用的ArrayList到底长啥样?

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

    其源代码如下:

     1  /**
     2    * @serial include
     3    */
     4   private static class ArrayList<E> extends AbstractList<E>
     5     implements RandomAccess, java.io.Serializable
     6   {
     7     private static final long serialVersionUID = -2764017481108945198L;
     8     private final E[] a;
     9 
    10     ArrayList(E[] array) {
    11       if (array==null)
    12         throw new NullPointerException();
    13       a = array;
    14     }
    15 
    16     public int size() {
    17       return a.length;
    18     }
    19 
    20     public Object[] toArray() {
    21       return a.clone();
    22     }
    23 
    24     public <T> T[] toArray(T[] a) {
    25       int size = size();
    26       if (a.length < size)
    27         return Arrays.copyOf(this.a, size,
    28                    (Class<? extends T[]>) a.getClass());
    29       System.arraycopy(this.a, 0, a, 0, size);
    30       if (a.length > size)
    31         a[size] = null;
    32       return a;
    33     }
    34 
    35     public E get(int index) {
    36       return a[index];
    37     }
    38 
    39     public E set(int index, E element) {
    40       E oldValue = a[index];
    41       a[index] = element;
    42       return oldValue;
    43     }
    44 
    45     public int indexOf(Object o) {
    46       if (o==null) {
    47         for (int i=0; i<a.length; i++)
    48           if (a[i]==null)
    49             return i;
    50       } else {
    51         for (int i=0; i<a.length; i++)
    52           if (o.equals(a[i]))
    53             return i;
    54       }
    55       return -1;
    56     }
    57 
    58     public boolean contains(Object o) {
    59       return indexOf(o) != -1;
    60     }
    61   }
    View Code

    从这个内部类ArrayList的实现可以看出,它继承了抽象类java.util.AbstractList<E>, 但是没有重写add和remove方法,没有给出具体的实现。

    但是,默认情况下,java.util.AbstractList类在add、set以及remove方法中,直接会抛出UnsupportedOperationException异常。AbstractList的部分源代码如下:

    public abstract class AbstractList<E> extends AbstractCollection<E> implements List<E> {
      /**
       * Sole constructor. (For invocation by subclass constructors, typically
       * implicit.)
       */
      protected AbstractList() {
      }
    
      public E set(int index, E element) {
        throw new UnsupportedOperationException();
      }
    
      /**
       * {@inheritDoc}
       *
       * <p>This implementation always throws an
       * {@code UnsupportedOperationException}.
       *
       * @throws UnsupportedOperationException {@inheritDoc}
       * @throws ClassCastException      {@inheritDoc}
       * @throws NullPointerException     {@inheritDoc}
       * @throws IllegalArgumentException   {@inheritDoc}
       * @throws IndexOutOfBoundsException   {@inheritDoc}
       */
      public void add(int index, E element) {
        throw new UnsupportedOperationException();
      }
    
      /**
       * {@inheritDoc}
       *
       * <p>This implementation always throws an
       * {@code UnsupportedOperationException}.
       *
       * @throws UnsupportedOperationException {@inheritDoc}
       * @throws IndexOutOfBoundsException   {@inheritDoc}
       */
      public E remove(int index) {
        throw new UnsupportedOperationException();
      }
    }
    View Code

    正是因为java.util.Arrays类的内部类ArrayList没有重写add和remove方法,所以,当我们调用其add方法时,其实就是调用了AbstractList类的add方法,结果就是直接抛出UnsupportedOperationException异常。

    同理,在调用remove方法,或者调用与add、remove方法相关联的其它方法(如addAll)同样会遇到UnsupportedOperationException异常。

    public class ArrayExample {
    
      public static void main(String[] args) {
    
        /**使用变长参数*/
        List<String> array1 = Arrays.asList("Welcome", "to", "Java", "world");
        array1.addAll(Arrays.asList("AAA", "BBB"));
      }
    
    }
    
    
    
    Exception in thread "main" java.lang.UnsupportedOperationException
     at java.util.AbstractList.add(Unknown Source)
     at java.util.AbstractList.add(Unknown Source)
     at java.util.AbstractCollection.addAll(Unknown Source)
     at test.ArrayExample.main(ArrayExample.java:36)
    

      

    set的例子:

    public class ArrayExample {
    
      public static void main(String[] args) {
    
        /**使用变长参数*/
        List<String> array1 = Arrays.asList("Welcome", "to", "Java", "world");
        System.out.println(array1);
        
        //将Java替换成hello
        array1.set(2, "hello");
        System.out.println(array1);
      }
    
    }
    

      

    正是由于Arrays的内部类ArrayList重写了set方法,所以上述程序能够正常运行,不会再抛出UnsupportedOperationException异常。

    结果如下:

    [Welcome, to, Java, world]
    [Welcome, to, hello, world] 

    Arrays.asList比较适合那些已经有数组数据或者一些元素,而需要快速构建一个List,只用于读取操作,而不进行添加或删除操作的场景。

    如果,想要根据已知数组数据,快速获取一个可进行增删改查的列表List,一个比较简单的方法如下:

    重新使用java.util.ArrayList包装一层。

    public class ArrayExample {
    
      public static void main(String[] args) {
    
        /**使用变长参数*/
        List<String> array1 = new ArrayList<>(Arrays.asList("Welcome", "to", "Java", "world"));
        System.out.println(array1);
    
        array1.add("Cool~~~");
        System.out.println(array1);
    
      }
    
    }
    

      

    结果如下:

    [Welcome, to, Java, world]
    [Welcome, to, Java, world, Cool~~~]

  • 相关阅读:
    ZABBIX实现原理及架构详解
    for(;;)和while(true)的区别
    JVM
    javap的基本用法
    Java VisualVM添加Visual GC插件
    Java虚拟机监控命令
    数据类型 原始类型的方法
    数据类型 数字类型
    Object(对象):基础知识 原型对象prototype
    Object(对象):基础知识 对象方法,"this"
  • 原文地址:https://www.cnblogs.com/JiangWJ/p/10802606.html
Copyright © 2020-2023  润新知