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 ...
随机推荐
- python3.7+flask+alipay 支付宝付款功能
文档参考github:https://github.com/fzlee/alipay/blob/master/docs/init.md 沙箱环境配置:https://opendocs.alipay.c ...
- 51nod1355-斐波那契的最小公倍数【min-max容斥】
正题 题目链接:http://www.51nod.com/Challenge/Problem.html#problemId=1355 题目大意 定义\(f_i\)表示斐波那契的第\(i\)项,给出一个 ...
- CF848E-Days of Floral Colours【dp,分治NTT】
正题 题目链接:https://www.luogu.com.cn/problem/CF848E 题目大意 \(2n\)个花排成一个圆环,\(n\)种颜色每种两个,要求两个相同颜色之间最小距离为\(1, ...
- 在windoes server2008部署kettle遇到的问题
本机电脑是windows10,在部署ketle时一切顺利,但在windows server2008服务器上部署,各种报错,毕竟线上环境比较复杂-- 问题一:启动kettle的spoon.bat文件时, ...
- CentOS7 Docker容器无法ping通宿主机ip问题解决记录
Docker服务部署启动容器发现docker容器内访问宿主机IP不通,于是进入容器内ping宿主机IP,发现无法ping通,容器IP为172.17.0.2,于是继续ping172.17.0.1也不通, ...
- 使用Stargate访问K8ssandra,Springboot整合Cassandra
1 简介 之前我们在文章<K8ssandra入门-详细记录在Linux上部署K8ssandra到Kubernetes>成功地在Ubuntu上安装了K8ssandra,现在我们来看看如何访问 ...
- HTML对溢出的控制:overflow
用于对超出模块的内容进行控制 overflow的三种参数 1.visible(默认):溢出部分可见 2.hidden:溢出部分隐藏 3.auto:适当加入滚动条 overflow使用方法 1.常用 o ...
- 熊猫分布密度制图(ArcPy实现)
一.背景 大熊猫是我国国家级珍惜保护动物,熊猫的生存必须满足一定槽域(独占的猎食与活动范围)条件.因此,科学准确的分析熊猫的分布情况,对合理制定保护措施和评价保护成效具有重要意义. 二.目的 通过练习 ...
- LeetCode352 将数据流变为多个不相交区间
LeetCode352 将数据流变为多个不相交区间 1 题目 给你一个由非负整数 a1, a2, ..., an 组成的数据流输入,请你将到目前为止看到的数字总结为不相交的区间列表. 实现 Summa ...
- Linux环境下安装java的方法
linux安装java步骤 方式一:yum方式下载安装 1.查找java相关的列表 yum -y list java* 或者 yum search jdk 2.安装jdk yum install ja ...