上一个建议之处了asList方法在转换基本类型数组时候存在的问题,在看下asList方法返回的列表有何特殊的地方.看代码:

  1. import java.util.Arrays;
  2. import java.util.List;
  3.  
  4. public class Client {
  5. //枚举,声明一个星期
  6. enum Week{Sun,Mon, Tue, Wed,Thu,Fri,Sat}
  7. public static void main(String[] args) {
  8. //工作日
  9. Week[] workDays = {Week.Mon, Week.Tue, Week.Wed,Week.Thu,Week.Fri};
  10. //转换为列表
  11. List<Week> list = Arrays.asList(workDays);
  12. //增加周六也为工作日
  13. list.add(Week.Sat);
  14.  
  15. /*工作日开始干活了*/
  16. }
  17. }

编译没有任何问题,运行结果:

  1. Exception in thread "main" java.lang.UnsupportedOperationException

不支持List的add方法,看asList的源代码.

  1. /**
  2. * Returns a fixed-size list backed by the specified array. (Changes to
  3. * the returned list "write through" to the array.) This method acts
  4. * as bridge between array-based and collection-based APIs, in
  5. * combination with {@link Collection#toArray}. The returned list is
  6. * serializable and implements {@link RandomAccess}.
  7. *
  8. * <p>This method also provides a convenient way to create a fixed-size
  9. * list initialized to contain several elements:
  10. * <pre>
  11. * List&lt;String&gt; stooges = Arrays.asList("Larry", "Moe", "Curly");
  12. * </pre>
  13. *
  14. * @param a the array by which the list will be backed
  15. * @return a list view of the specified array
  16. */
  17. @SafeVarargs
  18. public static <T> List<T> asList(T... a) {
  19. return new ArrayList<>(a);
  20. }

直接new 了一个ArrayList对象返回,难道ArrayList不支持add方法?问题就出在这个ArrayList类上,此ArrayList非java.util.ArrayList,而是Arrays工具类的一个内置类,其构造函数如下:

  1. //这是一个静态私有内部类
  2. private static class ArrayList<E> extends AbstractList<E>
  3. implements RandomAccess, java.io.Serializable
  4. {
  5. //存储列表元素的数组
  6. private final E[] a;
  7. //唯一的构造函数
  8. ArrayList(E[] array) {
  9. if (array==null)
  10. throw new NullPointerException();
  11. a = array;
  12. }
  13.  
  14. }

这个ArrayList是一个静态的私有内部类,除了Arrays能访问外,其他类都不能访问.仔细看这个类没有提供add方法,那肯定是父类AbstractList提供了,看代码:

  1. public boolean add(E e) {
  2. add(size(), e);
  3. return true;
  4. }
  5. public void add(int index, E element) {
  6. throw new UnsupportedOperationException();
  7. }

父类确实提供了,但没有提供具体的实现,所以每个子类都需要自己覆写add方法,而Arrays的内部类ArrayList没有覆写,因此add一个元素就会报错了.

我们再深入的看这个ArrayList静态内部类,它仅仅实现了5个方法:

1.size:元素数量

2.toArray:转化为数组,实现了数组的浅拷贝.

3.get:获得指定元素.

4.set:重置某一元素值.

5.contains:是否包含某一元素.

对于我们经常使用的List.add和List.remove方法它都没有实现了,也就是说asList返回的是一个长度不可变的列表,数组是多长,转换成的列表也就是多长.

换句话说此处的列表只是数组的一个外壳,不再保持列表变长的特性.这才是我们要关注的重点(虽然此处JDK的设计有悖于OO的设计原则,但是我们无力回天).

有些开发者喜欢如下定义和初始化列表:

  1. import java.util.Arrays;
  2. import java.util.List;
  3.  
  4. public class Client {
  5.  
  6. public static void main(String[] args) {
  7. List<String> names = Arrays.asList("张三","李四","王五");
  8.  
  9. }
  10. }

看似很便捷,却隐藏着重大的隐患-----列表长度无法修改.如果这样的一个List传递到一个允许add操作的方法中,那将会产生何种结果.

除非非常自信该List仅仅限于读操作.

附录Arrays中的静态内部类的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. }

[改善Java代码]asList方法产生的List对象不可更改的更多相关文章

  1. [改善Java代码]注意方法中传递的参数要求(replaceAll和replace的区别)

    有这样一个简单的需求:写一个方法,实现从原始字符串中删除与之匹配的所有子字符串,比如"蓝蓝的天,白云飘"中,删除"白云飘",输出"蓝蓝的天," ...

  2. 改善EF代码的方法(下)

    本节,我们将介绍一些改善EF代码的方法,包括编译查询.存储模型视图以及冲突处理等内容. > CompiledQuery 提供对查询的编译和缓存以供重新使用.当相同的查询需要执行很多遍的时候,那么 ...

  3. [改善Java代码]不同的列表选择不同的遍历方法

    一.场景: 我们来看一个场景,统计一个省的各科高考科目考试的平均分. 当然使用数据库中的一个SQL语句就能求出平均值,不过这个不再我们的考虑之列,这里只考虑使用纯Java的方式来解决.(由于我的机器配 ...

  4. [改善Java代码]覆写equals方法时不要识别不出自己

    建议45: 覆写equals方法时不要识别不出自己 我们在写一个JavaBean时,经常会覆写equals方法,其目的是根据业务规则判断两个对象是否相等,比如我们写一个Person类,然后根据姓名判断 ...

  5. [改善Java代码]避开基本类型数组转换列表陷阱

    开发中经常用到Arrays和Collections这两个工具类. 在数组和列表之间进行切换.非常方便.但是也会遇到一些问题. 看代码: import java.util.Arrays; import ...

  6. [改善Java代码]强制声明泛型的实际类型

    Arrays工具类有一个方法asList可以把一个变长参数或数组变成列表,但是它有一个缺点:它所生成的List长度是不可改变的,而这在我们的项目开发中很不方便. import java.util.Ar ...

  7. [改善Java代码]动态加载不适合数组

    上一个建议解释了为什么要使用forName,本建议就说说哪些地方不适合使用动态加载. 如果forName要加载一个类,那它必须是一个类------8中基本类型就排除在外.它们不是一个具体的类. 其次它 ...

  8. [改善Java代码]不要在构造函数中抛出异常

    Java的异常机制有三种: 一.Error类以及其子类表示的是错误,它是不需要程序员处理也不能处理的异常.比如VirtualMachineError虚拟机错误,ThreadDeath线程僵尸等. 二. ...

  9. [改善Java代码]易变业务使用脚本语言编写

    建议16: 易变业务使用脚本语言编写 Java世界一直在遭受着异种语言的入侵,比如PHP.Ruby.Groovy.JavaScript等,这些“入侵者”都有一个共同特征:全是同一类语言—脚本语言,它们 ...

随机推荐

  1. homework-04 单词方阵

    问题描述 本次作业的题目要求利用给定的一组单词生成一个矩阵,矩阵的每个位置由一个字母填充,单词表中的每一个单词可以匹配矩阵中一段连续的序列,这段序列可以是横向,纵向或者是45度斜角方向,单词可以由左向 ...

  2. CoffeeScript学习(3)—— 函数

    CoffeeScript函数 如果大家有看我之前关于ES6的箭头函数的话,这一篇也不会很难理解.我们这一次可以说一下,关于两者的一些细微差别. 基本 在CoffeeScript中,任何函数都是用箭头函 ...

  3. 获取iOS设备信息(内存/电量/容量/型号/IP地址/当前WIFI名称)

    1.获取电池电量(一般用百分数表示,大家自行处理就好) 1 2 3 4 -(CGFloat)getBatteryQuantity {         return [[UIDevice current ...

  4. Java封装 properties文件操作

    /** * Prop. Prop can load properties file from CLASSPATH or File object. */ public class Prop { priv ...

  5. CCS3.3入门

    CCS3安装包下载地址:http://pan.baidu.com/share/link?shareid=1887452332&uk=1799203308&qq-pf-to=pcqq.c ...

  6. URAL 2065 Different Sums (找规律)

    题意:构造一个数列,使得它们的区间和的种类最少,其中数列中不同的数的数目不少于k. 析:我们考虑0这个特殊的数字,然后0越多,那么总和种类最少,再就是正负交替,那么增加0的数量. 代码如下: #pra ...

  7. AngularJS~大话开篇

    AngularJS是一款优秀的前端JS框架,已经被用于Google的多款产品当中.AngularJS有着诸多特性,最为核心的是:MVVM.模块化.自动化双向数据绑定.语义化标签.依赖注入.等等. 前端 ...

  8. 【转】GCC使用简介

    Linux系统下的gcc(GNU C Compiler)是GNU推出的功能强大.性能优越的多平台编译器,是GNU的代表作品之一.gcc是可以在多种硬体平台上编译出可执行程序的超级编译器,其执行效率与一 ...

  9. 关于C++与Java中虚函数问题的读书笔记

    之前一直用C++编程,对虚函数还是一些较为肤浅的理解.可近期由于某些原因搞了下Java,发现有些知识点不熟,于是站在先驱巨人的肩上谈谈C++与Java中虚函数问题. Java中的虚函数 以下是段别人的 ...

  10. Educational Codeforces Round 1 E. Chocolate Bar 记忆化搜索

    E. Chocolate Bar Time Limit: 20 Sec Memory Limit: 256 MB 题目连接 http://codeforces.com/contest/598/prob ...