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 }

从这个内部类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();
}
}

正是因为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~~~]

JDK 之 Arrays.asList - 源码分析的更多相关文章

  1. JDK动态代理实现源码分析

    JDK动态代理实现方式 在Spring框架中经典的AOP就是通过动态代理来实现的,Spring分别采用了JDK的动态代理和Cglib动态代理,本文就来分析一下JDK是如何实现动态代理的. 在分析源码之 ...

  2. JDK 1.6 HashMap 源码分析

    前言 ​ 前段时间研究了一下JDK 1.6 的 HashMap 源码,把部份重要的方法分析一下,当然HashMap中还有一些值得研究得就交给读者了,如有不正确之处还望留言指正. 准备 ​ 需要熟悉数组 ...

  3. JDK的跳表源码分析

    JDK源码中的跳表实现类: ConcurrentSkipListMap和ConcurrentSkipListSet. 其中ConcurrentSkipListSet的实现是基于ConcurrentSk ...

  4. 【集合框架】JDK1.8源码分析之Collections && Arrays(十)

    一.前言 整个集合框架的常用类我们已经分析完成了,但是还有两个工具类我们还没有进行分析.可以说,这两个工具类对于我们操作集合时相当有用,下面进行分析. 二.Collections源码分析 2.1 类的 ...

  5. JDK Collection 源码分析(2)—— List

    JDK List源码分析 List接口定义了有序集合(序列).在Collection的基础上,增加了可以通过下标索引访问,以及线性查找等功能. 整体类结构 1.AbstractList   该类作为L ...

  6. JDK源码分析(5)Vector

    JDK版本 Vector简介 /** * The {@code Vector} class implements a growable array of * objects. Like an arra ...

  7. 【JDK】JDK源码分析-Vector

    概述 上文「JDK源码分析-ArrayList」主要分析了 ArrayList 的实现原理.本文分析 List 接口的另一个实现类:Vector. Vector 的内部实现与 ArrayList 类似 ...

  8. 【JDK】JDK源码分析-ArrayList

    概述 ArrayList 是 List 接口的一个实现类,也是 Java 中最常用的容器实现类之一,可以把它理解为「可变数组」. 我们知道,Java 中的数组初始化时需要指定长度,而且指定后不能改变. ...

  9. 7.Java集合-Arrays类实现原理及源码分析

    Java集合---Arrays类源码解析  转自:http://www.cnblogs.com/ITtangtang/p/3948765.html 一.Arrays.sort()数组排序 Java A ...

随机推荐

  1. P4321-随机漫游【状压dp,数学期望,高斯消元】

    正题 题目链接:https://www.luogu.com.cn/problem/P4321 题目大意 给出\(n\)个点\(m\)条边的一张无向图,\(q\)次询问. 每次询问给出一个点集和一个起点 ...

  2. P4199-万径人踪灭【FFT】

    正题 题目链接:https://www.luogu.com.cn/problem/P4199 题目大意 给出一个只包含\(a,b\)的字符串 求有多少个不连续的回文子序列(字母回文,位置对称) \(1 ...

  3. P4201-[NOI2008]设计路线【结论,树形dp】

    正题 题目链接:https://www.luogu.com.cn/problem/P4201 题目大意 给出\(n\)个点的一棵树开始所有边都是白色,选出若干条没有公共点的路径将上面所有边变为黑色. ...

  4. Oracle部署迁移手册

    第1章 安装准备 1.1 安装环境 操作系统:Redhat6.5 x64 32核CPU 62G内存 系统盘300G 数据磁盘3T Oracle软件:Oracle Database 11g Enterp ...

  5. 新一代容器平台ACK Anywhere,来了

    5G.AR.AIoT 等场景在推动新一代云架构的演进,而容器重塑了云的使用方式. 近日,阿里云容器服务全面升级为ACK Anywhere,让企业在任何需要云的地方,都能获得一致的容器基础设施能力. 早 ...

  6. Serverless 的初心、现状和未来

    作者 | 不瞋 导读:Serverless 是如何产生的?当前有哪些落地场景?Serverless 的未来又将如何?本文分享了阿里云高级技术专家不瞋对于 Serverless 的看法,回顾其发展历程, ...

  7. fastdfs单节点部署

    fastdfs单机版搭建 参考链接:https://blog.csdn.net/prcyang/article/details/89946190 搭建步骤 安装依赖 ​ yum -y install ...

  8. 【数据结构与算法Python版学习笔记】图——最短路径问题、最小生成树

    最短路径问题 概念 可以通过"traceroute"命令来跟踪信息传送的路径: traceroute www.lib.pku.edu.cn 可以将互联网路由器体系表示为一个带权边的 ...

  9. Linux argc,argv详解

    来源:微信公众号「编程学习基地」 @ 目录 argc,argv是什么 如何解析程序参数 "选项"是什么? "选项字符串"是什么 解析参数 argc,argv是什 ...

  10. 使用Servlet前Tomcat介绍

    虚拟目录的映射方式:让tomcat服务器自动映射tomcat服务器会自动管理webapps目录下的所有web应用,并把它映射成虚似目录.换句话说,tomcat服务器webapps目录中的web应用,外 ...