一、Java中数组

数组用来存放固定数量的同类元素,声明方法:

T[] ref,T ref[],如int[] intAry; int intAry[]。推荐用T[]的方式,后一种方式为兼容C++习惯写法。

初始化方法:

new设置数组长度,或者直接列出数组元素,如下:

 // 创建数组,如果在创建的同时不初始化数组则必须指定其大小
intArray0 = new int[3]; // 创建数组时,不指定数组大小则必须在创建的同时初始化数组
intArray1 = new int[]{0,1,2}; // 静态初始化简化方式
int intArray3 [] = {30,31,32};

二、Java 数组和集合之间的关系

世间上本来没有集合,(只有数组参考C语言)但有人想要,所以有了集合
有人想有可以自动扩展的数组,所以有了List
有的人想有没有重复的数组,所以有了set
有人想有自动排序的组数,所以有了TreeSet,TreeList,Tree** 而几乎有有的集合都是基于数组来实现的.
因为集合是对数组做的封装,所以,数组永远比任何一个集合要快 但任何一个集合,比数组提供的功能要多 一:数组声明了它容纳的元素的类型,而集合不声明。这是由于集合以object形式来存储它们的元素。 二:一个数组实例具有固定的大小,不能伸缩。集合则可根据需要动态改变大小。 三:数组是一种可读/可写数据结构---没有办法创建一个只读数组。然而可以使用集合提供的ReadOnly方法,以只读方式来使用集合。该方法将返回一个集合的只读版本。

注:java中可创建只读集合和同步集合,方法如下:

// 只读集合
List<String> readOnlyList = Collections.unmodifiableList(list);
System.out.println(readOnlyList.getClass());
// 同步集合
List<String> synchronizedList = Collections.synchronizedList(list);
System.out.println(synchronizedList.getClass());

如果试图对只读集合进行添加或修改,将会抛出UnsupportedOperationException异常:
如果不希望方法返回的集合被修改,就可以使用只读集合;如果想要获取线程安全的集合,就可以使用同步集合。

三、数组和集合的差异

数组array是固定大小不能动态改变,只能存同一种类型,可传递继承类型,即Number是Integer的父类,则Number[]是Integer[]的父类型,即可将Integer[]当做实参传入形参要求为Number[]的函数中。

集合是对数组能力的扩展,基于数据或链表结构实现,只能存放引用类型,不能存放基本类型;不能进行类型传递,即Listt<Number>不能看作List<Integer>的父类型。

四、数组集合的使用建议

建议65:避开基本类型数组转换列表陷阱

  我们在开发中经常会使用Arrays和Collections这两个工具类和列表之间转换,非常方便,但也有时候会出现一些奇怪的问题,来看如下代码: 

1 public class Client65 {
2 public static void main(String[] args) {
3 int data [] = {1,2,3,4,5};
4 List list= Arrays.asList(data);
5 System.out.println("列表中的元素数量是:"+list.size());
6 }
7 }

  也许你会说,这很简单,list变量的元素数量当然是5了。但是运行后打印出来的列表数量为1。

  事实上data确实是一个有5个元素的int类型数组,只是通过asList转换成列表后就只有一个元素了,这是为什么呢?其他4个元素到什么地方去了呢?

  我们仔细看一下Arrays.asList的方法说明:输入一个变长参数,返回一个固定长度的列表。注意这里是一个变长参数,看源码:

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

  asList方法输入的是一个泛型变长参数,我们知道基本类型是不能泛型化的,也就是说8个基本类型不能作为泛型参数,要想作为泛型参数就必须使用其所对应的包装类型,那前面的例子传递了一个int类型的数组,为何程序没有报编译错误呢?

  在Java中,数组是一个对象,它是可以泛型化的,也就是说我们的例子是把一个int类型的数组作为了T的类型,所以在转换后在List中就只有一个类型为int数组的元素了,我们打印出来看看,代码如下: 

1 public class Client65 {
2 public static void main(String[] args) {
3 int data [] = {1,2,3,4,5};
4 List list= Arrays.asList(data);
5 System.out.println("元素类型是:"+list.get(0).getClass());
6 System.out.println("前后是否相等:"+data.equals(list.get(0)));
7 }
8 }

  输出的结果是: 元素类型是:class [I   前后是否相等:true

  很明显,放在列表中的元素时一个int数组,可能有人要问了,为什么"元素类型:"后的class是"[I"?我们并没有指明是数组(Array)类型呀!这是因为JVM不可能输出Array类型,因为Array是属于java.lang.reflect包的,它是通过反射访问数组元素的工具类。在Java中任何一个一维数组的类型都是 " [I " ,究其原因就是Java并没有定义数组这一个类,它是在编译器编译的时候生成的,是一个特殊的类,在JDK的帮助中也没有任何数组类的信息。

  弄清楚了问题,修改也很easy,直接使用包装类即可,部分代码如下: 

Integer data [] = {1,2,3,4,5};

  把int替换为Integer即可让输出元素数量为5.需要说明的是,不仅仅是int类型的数组有这个问题,其它7个基本类型的数组也存在相似的问题,这就需要大家注意了,在把基本类型数组转换为列表时,要特别小心asList方法的陷阱,避免出现程序逻辑混乱的情况。

  注意:原始类型数组不能作为asList的输入参数,否则会引起程序逻辑混乱。

建议66:asList方法产生的List的对象不可更改

  上一个建议指出了asList方法在转换基本类型数组时存在的问题,接着我们看一下asList方法返回的列表有何特殊的地方,代码如下:  

 1 public class Client66 {
2 public static void main(String[] args) {
3 // 五天工作制
4 Week days[] = { Week.Mon, Week.Tue, Week.Wed, Week.Thu, Week.Fri };
5 // 转换为列表
6 List<Week> list = Arrays.asList(days);
7 // 增加周六为工作日
8 list.add(Week.Sat);
9 /* do something */
10 }
11 }
12 enum Week {
13 Sun, Mon, Tue, Wed, Thu, Fri, Sat
14 }

  很简单的程序呀,默认声明的工作日(workDays)是从周一到周五,偶尔周六也会算作工作日加入到工作日列表中,不过,这段程序执行时会不会有什么问题呢?编译没有任何问题,但是一运行,却出现了如下结果:

  

UnsupportedOperationException,不支持的操作,居然不支持list的add方法,这是什么原因呢?我们看看asList方法的源代码:

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

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

 1 private static class ArrayList<E> extends AbstractList<E>
2 implements RandomAccess, java.io.Serializable
3 {
4 private static final long serialVersionUID = -2764017481108945198L;
5 private final E[] a;
6
7 ArrayList(E[] array) {
8 if (array==null)
9 throw new NullPointerException();
10 a = array;
11 }
12 /*其它方法略*/
13 }

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

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

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

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

  1. size:元素数量
  2. get:获得制定元素
  3. set:重置某一元素值
  4. contains:是否包含某元素
  5. toArray:转化为数组,实现了数组的浅拷贝

  把这几个方法的源代码展示一下: 

 1  //元素数量
2 public int size() {
3 return a.length;
4 }
5
6 public Object[] toArray() {
7 return a.clone();
8 }
9 //转化为数组,实现了数组的浅拷贝
10 public <T> T[] toArray(T[] a) {
11 int size = size();
12 if (a.length < size)
13 return Arrays.copyOf(this.a, size,
14 (Class<? extends T[]>) a.getClass());
15 System.arraycopy(this.a, 0, a, 0, size);
16 if (a.length > size)
17 a[size] = null;
18 return a;
19 }
20 //获得指定元素
21 public E get(int index) {
22 return a[index];
23 }
24 //重置某一元素
25 public E set(int index, E element) {
26 E oldValue = a[index];
27 a[index] = element;
28 return oldValue;
29 }
30
31 public int indexOf(Object o) {
32 if (o==null) {
33 for (int i=0; i<a.length; i++)
34 if (a[i]==null)
35 return i;
36 } else {
37 for (int i=0; i<a.length; i++)
38 if (o.equals(a[i]))
39 return i;
40 }
41 return -1;
42 }
43 //是否包含元素
44 public boolean contains(Object o) {
45 return indexOf(o) != -1;
46 }

  对于我们经常使用list.add和list.remove方法它都没有实现,也就是说asList返回的是一个长度不可变的列表,数组是多长,转换成的列表也就是多长,换句话说此处的列表只是数组的一个外壳,不再保持列表的动态变长的特性,这才是我们关注的重点。有些开发人员喜欢这样定义个初始化列表: 

    List<String> names= Arrays.asList("张三","李四","王五");

  一句话完成了列表的定义和初始化,看似很便捷,却隐藏着重大隐患---列表长度无法修改。想想看,如果这样一个List传递到一个允许添加的add操作的方法中,那将会产生何种结果,如果有这种习惯的javaer,请慎之戒之,除非非常自信该List只用于只读操作。

针对ArrayList,使用高级for循环实质是通过Iterator来循环效率比基本for循环遍历元素稍差,在数据较多要用到性能时就不能为了简单用高级for循环。

频繁插入和删除元素时用LinkList,修改元素操作多时用ArrayList。

编写高质量代码:改善Java程序的151个建议(第5章:数组和集合___建议65~69)

Java中Array、List、Set、Map的更多相关文章

  1. JAVA 中的 Collection 和 Map 以及相关派生类的概念

    JAVA中Collection接口和Map接口的主要实现类   Collection接口 Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的 ...

  2. Java中集合List,Map和Set的区别

    Java中集合List,Map和Set的区别 1.List和Set的父接口是Collection,而Map不是 2.List中的元素是有序的,可以重复的 3.Map是Key-Value映射关系,且Ke ...

  3. Java中的Set,List,Map的区别

    1. 对JAVA的集合的理解是想对于数组 数组是大小固定的,并且同一个数组只能存放类型一样的数据(基本类型/引用类型) JAVA集合可以存储和操作数目不固定的一组数据. 所有的JAVA集合都位于 ja ...

  4. Java中集合List,Map和Set的差别

    Java中集合List,Map和Set的差别 1.List和Set的父接口是Collection.而Map不是 2.List中的元素是有序的,能够反复的 3.Map是Key-Value映射关系,且Ke ...

  5. Java-杂项: Java中Array和ArrayList区别

    ylbtech-Java-杂项: Java中Array和ArrayList区别 1.返回顶部 1. 1)精辟阐述:可以将 ArrayList想象成一种“会自动扩增容量的Array”. 2)Array( ...

  6. JAVA中Collection接口和Map接口的主要实现类

    Collection接口 Collection是最基本的集合接口,一个Collection代表一组Object,即Collection的元素(Elements).一些Collection允许相同的元素 ...

  7. Java中的Set, List, Map漫谈

    在编程语言中,集合是指代表一组对象的对象.Java平台专门有一个集合框架(Collections Framework).集合框架是指表示和操作集合的统一架构,隔离了集合的操作和实现细节. 集合框架中的 ...

  8. Java中Array的常用方法

    0.创建/声明一个数组 1 2 3 String[] aArray = new String[5]; String[] bArray = {"a","b",&q ...

  9. 【Java集合的详细研究5】Java中Array与ArrayList的主要区别

    1)精辟阐述:可以将 ArrayList想象成一种“会自动扩增容量的Array”. 2)Array([]):最高效:但是其容量固定且无法动态改变:     ArrayList:  容量可动态增长:但牺 ...

随机推荐

  1. NSLayoutConstraint的使用

    *一切皆代码*- -- #继承关系框架|类|类:-:|:-:|:-:UIKit|NSLayoutConstraint|--|-|- #应用场景UI界面的搭建一般会占用项目开发相当一部分的时间.涉及到控 ...

  2. C++关键字简述

    ID 范畴 关键字 说明 1 数据类型 bool 基本类型—-布尔类型 2 数据类型 char 基本类型—-字符类型 3 数据类型 wchar_t 基本类型—-宽字符类型 4 数据类型 double ...

  3. Vim常用又容易忘的命令

    一篇讲的不错的教程 :noh 取消搜索高亮 x 删当前光标所在的一个字符. :wq 存盘 + 退出 dd 删除当前行,并把删除的行存到剪贴板里 p 粘贴剪贴板 a → 在光标后插入 /pattern ...

  4. how does Array.prototype.slice.call() work?

    763 down vote accepted +50 What happens under the hood is that when .slice() is called normally, thi ...

  5. Drop it FreeCodeCamp

    function drop(arr, func) { // Drop them elements. for(var start=0 ;start<arr.length; start++){ if ...

  6. IDEA 社区版 点击‘Edit Configurations’打开“Run/Debug Configurations”,里面没有tomcat server选项

    没错 社区版就是没有 “先手动添加Plugins 然后再setting” 方法无效 搜索不到 http://blog.csdn.net/u010666884/article/details/52119 ...

  7. 算法61---两个字符串的最小ASCII删除和【动态规划】

    一.题目: 给定两个字符串s1, s2,找到使两个字符串相等所需删除字符的ASCII值的最小和. 示例 1: 输入: s1 = "sea", s2 = "eat" ...

  8. POJ 2115 C Looooops( 简单拓欧 + 快速幂 )

    链接:传送门 题意:题目中给出一个循环 for (variable = A; variable != B; variable += C) ,这个东东还需要 mod 2^k 问至少多次能退出,如果进入死 ...

  9. J2EE提高之知识清单

    Oracle数据库 JDBC事务 Spring事务 SOA XML/JSON redis/memcached 反射,类加载,JVM 工具类:UML, Maven, 性能类:CPU监控,memary监控 ...

  10. sax解析xml文件的DefaultHandler处理类

    一千年的时光,我无数次掀起岁月的帷幔,只为和你,在某一个平静如水的日子相遇,然后相识,倾情一生,缱绻一世,好美的散文,好吧,我情愿把这个“你”当作android:),使用sax解析xml文件是我见到过 ...