在实际开发过程中我们经常使用 asList 讲数组转换为 List,这个方法使用起来非常方便,但是 asList 方法存在几个缺陷:

一、避免使用基本数据类型数组转换为列表

使用 8 个基本类型数组转换为列表时会存在一个比较有味的缺陷。先看如下程序:


public static void main(String[] args) {
int[] ints = {1,2,3,4,5};
List list = Arrays.asList(ints);
System.out.println("list'size:" + list.size());
}
------------------------------------
outPut:
list'size:1

程序的运行结果并没有像我们预期的那样是 5 而是逆天的 1,这是什么情况?先看源码:


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

asList 接受的参数是一个泛型的变长参数,我们知道基本数据类型是无法发型化的,也就是说 8 个基本类型是无法作为 asList 的参数的, 要想作为泛型参数就必须使用其所对应的包装类型。但是这个这个实例中为什么没有出错呢?因为该实例是将 int 类型的数组当做其参数,而在 Java 中数组是一个对象,它是可以泛型化的。所以该例子是不会产生错误的。既然例子是将整个 int 类型的数组当做泛型参数,那么经过 asList 转换就只有一个 int 的列表了。如下:


public static void main(String[] args) {
int[] ints = {1,2,3,4,5};
List list = Arrays.asList(ints);
System.out.println("list 的类型:" + list.get(0).getClass());
System.out.println("list.get(0) == ints:" + list.get(0).equals(ints));
}
--------------------------------------------
outPut:
list 的类型:class [I
list.get(0) == ints:true

从这个运行结果我们可以充分证明 list 里面的元素就是 int 数组。弄清楚这点了,那么修改方法也就一目了然了:将 int 改变为 Integer。


public static void main(String[] args) {
Integer[] ints = {1,2,3,4,5};
List list = Arrays.asList(ints);
System.out.println("list'size:" + list.size());
System.out.println("list.get(0) 的类型:" + list.get(0).getClass());
System.out.println("list.get(0) == ints[0]:" + list.get(0).equals(ints[0]));
}
----------------------------------------
outPut:
list'size:5
list.get(0) 的类型:class java.lang.Integer
list.get(0) == ints[0]:true

Java 细节(2.1):在使用 asList 时不要将基本数据类型当做参数。

二、asList 产生的列表不可操作

对于上面的实例我们再做一个小小的修改:


public static void main(String[] args) {
Integer[] ints = {1,2,3,4,5};
List list = Arrays.asList(ints);
list.add(6);
}

该实例就是讲 ints 通过 asList 转换为 list 类别,然后再通过 add 方法加一个元素,这个实例简单的不能再简单了,但是运行结果呢?打出我们所料:


Exception in thread "main" java.lang.UnsupportedOperationException
at java.util.AbstractList.add(Unknown Source)
at java.util.AbstractList.add(Unknown Source)
at com.chenssy.test.arrayList.AsListTest.main(AsListTest.java:10)

运行结果尽然抛出 UnsupportedOperationException 异常,该异常表示 list 不支持 add 方法。这就让我们郁闷了,list 怎么可能不支持 add 方法呢?难道 JDK 脑袋堵塞了?我们再看 asList 的源码:


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

asList 接受参数后,直接 new 一个 ArrayList,到这里看应该是没有错误的啊?别急,再往下看:


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;
}
//.................
}

这是 ArrayList 的源码,从这里我们可以看出,此 ArrayList 不是 java.util.ArrayList,他是 Arrays 的内部类。该内部类提供了 size、toArray、get、set、indexOf、contains 方法,而像 add、remove 等改变 list 结果的方法从 AbstractList 父类继承过来,同时这些方法也比较奇葩,它直接抛出 UnsupportedOperationException 异常:


public boolean add(E e) {
add(size(), e);
return true;
} public E set(int index, E element) {
throw new UnsupportedOperationException();
} public void add(int index, E element) {
throw new UnsupportedOperationException();
} public E remove(int index) {
throw new UnsupportedOperationException();
}

通过这些代码可以看出 asList 返回的列表只不过是一个披着 list 的外衣,它并没有 list 的基本特性(变长)。该 list 是一个长度不可变的列表,传入参数的数组有多长,其返回的列表就只能是多长。所以:

from: http://wiki.jikexueyuan.com/project/java-enhancement/java-thirtysix.html

Java 集合细节(二):asList 的缺陷的更多相关文章

  1. Java提高篇(三五)-----Java集合细节(一):请为集合指定初始容量

    集合是我们在Java编程中使用非常广泛的,它就像大海,海纳百川,像万能容器,盛装万物,而且这个大海,万能容器还可以无限变大(如果条件允许).当这个海.容器的量变得非常大的时候,它的初始容量就会显得很重 ...

  2. (Set, Map, Collections工具类)JAVA集合框架二

    Java集合框架部分细节总结二 Set 实现类:HashSet,TreeSet HashSet 基于HashCode计算元素存放位置,当计算得出哈希码相同时,会调用equals判断是否相同,相同则拒绝 ...

  3. 【由浅入深理解java集合】(二)——集合 Set

    上一篇文章介绍了Set集合的通用知识.Set集合中包含了三个比较重要的实现类:HashSet.TreeSet和EnumSet.本篇文章将重点介绍这三个类. 一.HashSet类 HashSet简介 H ...

  4. java 集合框架(二)Iterable接口

    Iterable接口是java 集合框架的顶级接口,实现此接口使集合对象可以通过迭代器遍历自身元素,我们可以看下它的成员方法 修饰符和返回值 方法名 描述 Iterator<T> iter ...

  5. Java集合系列(二):ArrayList、LinkedList、Vector的使用方法及区别

    本篇博客主要讲解List接口的三个实现类ArrayList.LinkedList.Vector的使用方法以及三者之间的区别. 1. ArrayList使用 ArrayList是List接口最常用的实现 ...

  6. Java提高篇(三六)-----Java集合细节(二):asList的缺陷

    在实际开发过程中我们经常使用asList讲数组转换为List,这个方法使用起来非常方便,但是asList方法存在几个缺陷: 一.避免使用基本数据类型数组转换为列表 使用8个基本类型数组转换为列表时会存 ...

  7. Java提高配(三七)-----Java集合细节(三):subList的缺陷

    我们经常使用subString方法来对String对象进行分割处理,同时我们也可以使用subList.subMap.subSet来对List.Map.Set进行分割处理,但是这个分割存在某些瑕疵. 一 ...

  8. [知识整理]Java集合(二) - Set

    一.实现Set的几个类 HashSet.LinkedHashSet.TreeSet.ConcurrentSkipListSet.CopyOnWriterArraySet 二.对应底层的数据结构 Has ...

  9. Java提高篇(三八)-----Java集合细节(四):保持compareTo和equals同步

    在Java中我们常使用Comparable接口来实现排序,其中compareTo是实现该接口方法.我们知道compareTo返回0表示两个对象相等,返回正数表示大于,返回负数表示小于.同时我们也知道e ...

随机推荐

  1. 高能天气——团队Scrum冲刺阶段-Day 1-领航

    高能天气--团队Scrum冲刺阶段-Day 1-领航 各个成员在 Alpha 阶段认领的任务 经过重新的团队讨论,我们最新确定的α版本所需实现内容如下: 查找城市:切换城市按钮.滑动界面视图 天气预报 ...

  2. 【翻译】checkbox的第三种状态

    checkbox只有两种值:选中(checked)或未选中(unchecked).它可以有任何值,但是表单提交时checkbox的值只能是checked或unchecked.它的默认值是uncheck ...

  3. 400+节点的 Elasticsearch 集群运维

    本文首发于InfoQ https://www.infoq.cn/article/1sm0Mq5LyY_021HGuXer 作者:Anton Hägerstrand 翻译:杨振涛 目录: 数据量 版本 ...

  4. InnoDB的锁机制浅析(一)—基本概念/兼容矩阵

    InnoDB锁的基本概念 文章总共分为五个部分: InnoDB的锁机制浅析(一)-基本概念/兼容矩阵 InnoDB的锁机制浅析(二)-探索InnoDB中的锁(Record锁/Gap锁/Next-key ...

  5. web前端实现本地存储

    当我们在提及web前端本地存储的时候,首先需要介绍一下本地化存储的概念和历史.本地化存储从来不是一个新奇的概念,因为web应用程序一直在追求的就是媲美甚至超越桌面应用程序.但是桌面应用程序一直优于we ...

  6. BZOJ.2716.[Violet3]天使玩偶(CDQ分治 坐标变换)

    题目链接 考虑对于两个点a,b,距离为|x[a]-x[b]|+|y[a]-y[b]|,如果a在b的右上,那我们可以把绝对值去掉,即x[a]+y[a]-(x[b]+y[b]). 即我们要求满足x[b]& ...

  7. NOI.AC NOIP模拟赛 第一场 补记

    NOI.AC NOIP模拟赛 第一场 补记 candy 题目大意: 有两个超市,每个超市有\(n(n\le10^5)\)个糖,每个糖\(W\)元.每颗糖有一个愉悦度,其中,第一家商店中的第\(i\)颗 ...

  8. [POI2013]Usuwanka

    [POI2013]Usuwanka 题目大意: 一排\(n\)个球,有黑白两种颜色.每取走一个球会在原位置放一个水晶球.求构造一种取球方案,满足: 每次取走\(k\)个白球和\(1\)个黑球: 一次取 ...

  9. Node.js数据库连接池操作通用工具(MySQL模块)

    出处:OSN开源站点数据库通用工具类,OSN源代码地址,https://github.com/obullxl/osnode-site,百度云演示站点,http://obullxl.duapp.com使 ...

  10. DMA Stream/Channel Outputting via GPIOC[0..7]

    Ok, so quickly mashing up another example using a different TIM, DMA Stream/Channel for illustration ...