Collection使用详解

  在使用Java语言开发时,绕不开对集合的使用,因此,对集合的掌握是非常有必要的。除此之外,Java的集合框架设计也能看出一些数据结构的设计思想,对开发的进阶是很有帮忙的。

一、集合框架概述

  谈Java集合框架,基本上绕不开一张图,如下:

  从上图可以看出,Java 集合框架主要包括两种类型的容器,一种是Collection,存储元素集合;另一种是Map,存储键/值对映射。Collection 接口又有 3 种子类型,List、Set 和 Queue,再下面是一些抽象类,最后是具体实现类,常用的有 ArrayList、LinkedList、HashSet、LinkedHashSet、HashMap、LinkedHashMap 等。
  将这些子接口或实现类用一个简单的图来表示,如下:

二、Collection接口

2.1 List

  使用List存储的特点:元素有序、可重复。常用的实现方式:ArrayList、Vector和LinkedList。

具体实现 优点 缺点
ArrayList 底层数据结构是数组,查询快,效率高 增删慢, 线程不安全
Vector 底层数据结构是数组,查询快,线程安全 增删慢,效率低
LinkedList 底层数据结构是链表,增删快,效率高 查询慢, 线程不安全

  ArrayList是一个动态数组,随着容器中的元素不断增加,容器的大小也会随着增加。同时由于ArrayList底层是数组实现,所以可以随机访问元素。
  Vector与ArrayList类似,不过是同步的,因此Vector是线程安全的动态数组。此外, Stack继承自Vector,实现一个后进先出的堆栈。
  LinkedList是一个双向链表,LinkedList不能随机访问,增删元素比较方便。

2.2 Set

  使用Set存储的特点与List相反:元素无序、不可重复。常用的实现方式:HashSet、LinkedHashSet和TreeSet。

具体实现 优点 缺点
HashSet 底层数据结构是哈希表,可以存储null元素,效率高 线程不安全,需要从重写hashCode()和equals()来保证元素唯一性
LinkedHashSet 底层数据结构是链表和哈希表(链表保证了元素的顺序与存储顺序一致,哈希表保证了元素的唯一性),效率高 线程不安全
TreeSet 底层数据结构是二叉树,元素唯一且已经排好序 需要重写hashCode和equals()来保证元素唯一性

  在使用Set存储数据时,为保障元素唯一性,常常要重写hashCode。重写hashCode方法时,尽量遵循以下原则:
   1>相同的对象返回相同的hashCode值
   2>不同的对象返回不同的hashCode值,否则,就会增加冲突的概率
   3>尽量的让hashCode值散列开(用异或运算可使结果的范围更广)
  HashSet中没有重复元素,底层由HashMap实现,不保证元素的顺序(此处的没有顺序是指:元素插入的顺序与输出的顺序不一致),HashSet允许使用null 元素,HashSet是非同步的。
  LinkedHashSet继承自HashSet,其底层是基于LinkedHashMap来实现的,有序,非同步。
  TreeSet底层是基于TreeMap实现的,所以元素有序。TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。当我们构造TreeSet时,若使用不带参数的构造函数,则TreeSet的使用自然比较器;若用户需要使用自定义的比较器,则需要使用带比较器的参数。TreeSet是非同步的。
  自然排序要求元素必须实现Compareable接口,并重写里面的compareTo()方法,元素通过比较返回的int值来判断排序序列,返回0说明两个对象相同;比较器排需要在TreeSet初始化是时候传入一个实现Comparator接口的比较器对象,或者采用匿名内部类的方式new一个Comparator对象,重写里面的compare()方法。
  在使用Set存储元素时,元素虽然无放入顺序,但Set的底层实现其实是Map,元素在Set中的位置是有该元素的HashCode决定的,所以其位置其实是固定的。
  至于具体使用哪个集合时,参考如下:

  在List和Set两个分支中,ArrayList和HashSet是对应分支中适应性最广的,两者再比较,ArrayList则适用性更广一些。也就是说如果要确定用List,但不确定用哪种List,就可以使用ArrayList;如果确定用Set,但不确定用哪种Set,就可以使用HashSet。如果只知道用集合,就用ArrayList。

三、Map接口

  Map由一系列键值对组成的集合,提供了key到Value的映射。在Map中它保证了key与value之间的一一对应关系,即一个key对应一个value,所以不能存在相同的key值,value值可以相同。
  常用的Map有:HashMap、LinkedHashMap、TreeMap和HashTable。

具体实现 优点 缺点
HashMap 基于哈希表实现,查询快,效率高 元素存储时无序,非线程安全
LinkedHashMap 基于哈希表和链表实现,可以保留元素插入时的顺序 非线程安全
TreeMap 存储的元素有序 非线程安全
HashTable 线程安全,不允许null值 效率低

  至于具体使用哪个Map时,参考如下:

  在Map中,HashMap是对应分支中适应性最广的。也就是说如果要确定用Map,但不确定用哪种Map,就可以使用HashMap。

四、相似集合的比较

  4.1>ArrayList和LinkedList
   1>ArrayList基于动态数组,LinkedList基于链表。
   2>对于随机访问操作,ArrayList绝对优于LinkedList,因为LinkedList要移动指针。
   3>对于增删操作,LinedList比较占优势,因为ArrayList要移动数据。
  4.2>HashTable和HashMap
   1>同步性:HashTable是线程安全的,也就是说是同步的,而HashMap是线程序不安全的,不是同步的 (如果需要同步,可以用Collections的synchronizedMap方法使HashMap具有同步的能力)。
   2>效率:HashTable效率最低,HashMap效率最高 。
   3>对null值的处理:HashMap的key、value都可为null,不过HashMap最多只允许一条记录的键为Null;允许多条记录的值为Null。;HashTable的key、value都不可为null 。
   4>支持的遍历种类不同:HashMap只支持Iterator遍历。而Hashtable支持Iterator和Enumeration两种方式遍历。
  4.3>LinkedHashMap和TreeMap
  LinkedHashMap保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的,也可以在构造时用带参数,按照应用次数排序。
  TreeMap实现SortMap接口,内部实现是红黑树。能够把它保存的记录根据键排序,默认是按键值的升序排序,也可以指定排序的比较器,当用Iterator 遍历TreeMap时,得到的记录是排过序的。TreeMap不允许key的值为null。非同步的。
  4.4>HashSet、LinkedHashSet和TreeSet
  当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值也相等。
  LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
  LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。
  TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
  TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0。

五、从类名看特点

  以下内容可以作为快速判断一种集合特点的参考:
  Array***:底层数据结构是数组,查询快,增删慢。
  Linked***:底层数据结构是链表,查询慢,增删快。
  Hash***:底层数据结构是哈希表,元素相同与否取决于两个方法:hashCode()和equals()。
  Tree***:底层数据结构是二叉树,元素比较的两种方式:自然排序和比较器排序。

猜你喜欢

转载自blog.csdn.net/m0_37741420/article/details/106884159