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 }
从这个内部类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 - 源码分析的更多相关文章
- JDK动态代理实现源码分析
JDK动态代理实现方式 在Spring框架中经典的AOP就是通过动态代理来实现的,Spring分别采用了JDK的动态代理和Cglib动态代理,本文就来分析一下JDK是如何实现动态代理的. 在分析源码之 ...
- JDK 1.6 HashMap 源码分析
前言 前段时间研究了一下JDK 1.6 的 HashMap 源码,把部份重要的方法分析一下,当然HashMap中还有一些值得研究得就交给读者了,如有不正确之处还望留言指正. 准备 需要熟悉数组 ...
- JDK的跳表源码分析
JDK源码中的跳表实现类: ConcurrentSkipListMap和ConcurrentSkipListSet. 其中ConcurrentSkipListSet的实现是基于ConcurrentSk ...
- 【集合框架】JDK1.8源码分析之Collections && Arrays(十)
一.前言 整个集合框架的常用类我们已经分析完成了,但是还有两个工具类我们还没有进行分析.可以说,这两个工具类对于我们操作集合时相当有用,下面进行分析. 二.Collections源码分析 2.1 类的 ...
- JDK Collection 源码分析(2)—— List
JDK List源码分析 List接口定义了有序集合(序列).在Collection的基础上,增加了可以通过下标索引访问,以及线性查找等功能. 整体类结构 1.AbstractList 该类作为L ...
- JDK源码分析(5)Vector
JDK版本 Vector简介 /** * The {@code Vector} class implements a growable array of * objects. Like an arra ...
- 【JDK】JDK源码分析-Vector
概述 上文「JDK源码分析-ArrayList」主要分析了 ArrayList 的实现原理.本文分析 List 接口的另一个实现类:Vector. Vector 的内部实现与 ArrayList 类似 ...
- 【JDK】JDK源码分析-ArrayList
概述 ArrayList 是 List 接口的一个实现类,也是 Java 中最常用的容器实现类之一,可以把它理解为「可变数组」. 我们知道,Java 中的数组初始化时需要指定长度,而且指定后不能改变. ...
- 7.Java集合-Arrays类实现原理及源码分析
Java集合---Arrays类源码解析 转自:http://www.cnblogs.com/ITtangtang/p/3948765.html 一.Arrays.sort()数组排序 Java A ...
随机推荐
- P4606-[SDOI2018]战略游戏【圆方树,虚树】
正题 题目链接:https://www.luogu.com.cn/problem/P4606 题目大意 给出\(n\)个点\(m\)条边的一张图,\(q\)次询问给出一个点集,询问有多少个点割掉后可以 ...
- 使用gitlab runner进行CI(三):使用sonarqube做c++的静态检查
目录 1. gitlab-ci.yml的配置 1.1 几个基本概念 1.2 使用CI进行代码检查demo 2. Sonarqube安装和配置 2.1 Sonarqube安装 2.2 数据库配置 2.3 ...
- window.postMessage 在iframe父子页面数据传输
介绍 https://developer.mozilla.org/zh-CN/docs/Web/API/Window/postMessage window.postMessage 发送方 接收方 示例 ...
- 在 ASP.NET Core 中自动启用 CAP 事务
本篇文章旨在描述如何在 ASP.NET Core项目中并以一种简便的方式启用CAP事务,因为在我们的示例中都是直接演示比较直观的方式,没有进行封装,有些初学者同学不太会,找到问我如何封装,本篇文章主要 ...
- 利用caffe.proto生成caffe.pb.h
完全按照博文来就好了:http://blog.csdn.net/u012905422/article/details/52794693
- 题解「2017 山东一轮集训 Day1 / SDWC2018 Day1」Set
题目传送门 题目大意 给出一个长度为 \(n\) 的数组,选出一些数异或之和为 \(s1\),其余数异或之和为 \(s2\),求 \(s1+s2\) 最大时 \(s1\) 的最小值. 思路 你发现如果 ...
- SpringBoot入门05-全局配置文件
springboot全局配置文件作用是设置或修改默认设置 springboot全局配置文件有下面两种方式 application.xml配置文件 示例 server.port=8088 server. ...
- Excel一对多查找
很多人在Excel中用函数公式做查询的时候,都必然会遇到的一个大问题,那就是一对多的查找/查询公式应该怎么写?大多数人都是从VLOOKUP.INDEX+MATCH中入门的,纵然你把全部的多条件查找方法 ...
- 微信h5跳转小程序wx-open-launch-weapp开放标签不显示(已解决)
前言: 前几天成功对接了跳转第三方小程序的功能,今天有个页面有需要对接.但是奇怪的是用的和上次一模一样的配置,但就是死活不显示wx-open-launch-weapp这个开放标签的按钮,看不到任何效果 ...
- Framework - 性能统计
摘要 近期对接客户时,客户方希望提供 SDK 的性能.内存.隐私支持等一些数据,所以就对 SDK 进行了一些性能测试. 在用表格统计整理这些数据时,突然发现,经常用统计的方式看 SDK 的相关数据,似 ...