这篇文章主要介绍了 java 源码分析 Arrays.asList 方法详解的相关资料, 需要的朋友可以参考下
最近, 抽空把 java Arrays 工具类的 asList 方法做了源码分析, 在网上整理了相关资料, 记录下来, 希望也能帮助读者!
Arrays 工具类提供了一个方法 asList, 使用该方法可以将一个变长参数或者数组转换成 List
其源代码如下:
- /**
- * Returns a fixed-size list backed by the specified array. (Changes to
- * the returned list "write through" to the array.) This method acts
- * as bridge between array-based and collection-based APIs, in
- * combination with {@link Collection#toArray}. The returned list is
- * serializable and implements {@link RandomAccess}.
- *
- * <p>This method also provides a convenient way to create a fixed-size
- * list initialized to contain several elements:
- * <pre>
- * List<String> stooges = Arrays.asList("Larry", "Moe", "Curly");
- * </pre>
- *
- * @param a the array by which the list will be backed
- * @return a list view of the specified array
- */
- @SafeVarargs
- public static <T> List<T> asList(T... a) {
- return new ArrayList<>(a);
- }
问题发现
根据上述方法的描述, 我们先来编写几个例子:
- /**
- * @author wangmengjun
- *
- */
- 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 类
其源代码如下:
- /**
- * @serial include
- */
- 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;
- }
- public int size() {
- return a.length;
- }
- public Object[] toArray() {
- return a.clone();
- }
- public <T> T[] toArray(T[] a) {
- int size = size();
- if (a.length < size)
- return Arrays.copyOf(this.a, size,
- (Class<? extends T[]>) a.getClass());
- System.arraycopy(this.a, 0, a, 0, size);
- if (a.length > size)
- a[size] = null;
- return a;
- }
- public E get(int index) {
- return a[index];
- }
- public E set(int index, E element) {
- E oldValue = a[index];
- a[index] = element;
- return oldValue;
- }
- public int indexOf(Object o) {
- if (o==null) {
- for (int i=0; i<a.length; i++)
- if (a[i]==null)
- return i;
- } else {
- for (int i=0; i<a.length; i++)
- if (o.equals(a[i]))
- return i;
- }
- return -1;
- }
- public boolean contains(Object o) {
- return indexOf(o) != -1;
- }
- }
从这个内部类 ArrayList 的实现可以看出, 它继承了抽象类 java.util.AbstractList<E>, 但是没有重写 add 和 remove 方法, 没有给出具体的实现
但是, 默认情况下, java.util.AbstractList 类在 addset 以及 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();
- }
- }
正是因为 java.util.Arrays 类的内部类 ArrayList 没有重写 add 和 remove 方法, 所以, 当我们调用其 add 方法时, 其实就是调用了 AbstractList 类的 add 方法, 结果就是直接抛出 UnsupportedOperationException 异常
同理, 在调用 remove 方法, 或者调用与 addremove 方法相关联的其它方法 (如 addAll) 同样会遇到 UnsupportedOperationException 异常
addAll 的例子:
- /**
- * @author wangmengjun
- *
- */
- 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 的例子:
- /**
- * @author wangmengjun
- *
- */
- 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 的长度是固定的; 能够进行修改操作 (比如, 修改某个位置的元素); 不能执行影响长度的操作(如 addremove 等操作) 会抛出 UnsupportedOperationException 异常
Arrays.asList 比较适合那些已经有数组数据或者一些元素, 而需要快速构建一个 List, 只用于读取操作, 而不进行添加或删除操作的场景
如果, 想要根据已知数组数据, 快速获取一个可进行增删改查的列表 List, 一个比较简单的方法如下:
重新使用 java.util.ArrayList 包装一层
- /**
- * @author wangmengjun
- *
- */
- 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~~~]
来源: http://www.phperz.com/article/18/0221/359651.html