集合包是Java中最常用的包,它最常用的有Collection和Map两个接口的实现类,Collection用于存放多个单对象,Map用于存放Key-Value形式的键值对。
Collection中常用的又分为两种类型的接口:List和Set,两者最明显的差别为List支持放入重复的对象,而Set不支持。List接口常用的实现类有:ArrayList,LinkedList,Vector和Stack;Set接口常用的实现有HashSet,TreeSet。而Map的常用实现有TreeMap和HashMap。
一、ArrayList
1. ArrayList基于数组方式实现,无容量的限制。
2. ArrayList在执行插入元素时可能要扩容,在删除数组时并不会减少数组的容量(如希望相应的减少数组的容量,可以调用ArrayList的trimToSize()),在查找元素时需要遍历数组,对于非null的元素采取equals的方式寻找。
3.ArrayList是非线程安全的。
二、LinkedList
1. LinkedList基于双向链表机制实现。
2. LinkedList在插入元素时,必须创建一个新的Entry对象,并切换相应元素的前后元素的引用;在查找元素时,须遍历列表;在删除元素时,要遍历列表,找到要删除的元素,然后从列表上将此元素删除即可。
3. LinkedList是非线程安全的。
从LinkedList和ArrayList的区别来看,我们可容易的得出什么时候使用ArrayList,什么时候使用LinkedList:
1)对于随机访问get和set,ArrayList优于LinkedList,因为LinkedList要移动指针。
2) 对于新增和删除操作add和remove,LinedList比较占优势,因为ArrayList要移动数据。
三、Vector
和ArrayList的不同点有
1) Vector是基于Synchronized实现的线程安全的ArrayList。即Vector是线程安全的。
2)在插入元素时容量扩充的机制和ArrayList稍微有所不同,Vector是扩充2倍,并可通过传入capacityIncrement来控制容量的扩充。而ArrayList是扩充1.5倍并加1。
四、Stack
Stack继承与Vector,在Vector的基础上实现了Stack所要求的后进先出(LIFO)的弹出即压入操作,其提供了push,pop,peek等三个主要方法。
五、HashSet
1. HashSet基于HashMap实现,无容量限制。
2. HashSet是非线程安全的。
3. HashSet不保证有序。
六、TreeSet
1、TreeSet基于TreeMap实现,支持排序。
2、TreeSet是非线程安全的。
从对HashSet和TreeSet的描述来看,TreeSet和HashSet一样,也是完全基于Map来实现的,并且都不支持get(int)来获取指定位置的元素(需要遍历获取),另外TreeSet还提供了一些排序方面的支持。例如传入Comparator实现、descendingSet以及descendingIterator等。
七、LinkedHashSet:
1. LinkedHashSet 以元素插入的顺序来维护集合的链接表,允许以插入的顺序在集合中迭代
2. LinkedHashSet同样是非线程安全的。
在同步并发环境下,为了确保Set是线程安全的,可以使用Collections.synchronizedSet(new HashSet());因为其能够返回原始hashset集合的同步版本,在多线程环境中可以访问这个同步版本。
LinkedHashSet, HashSet,TreeSet三者的区别:
HashSet:哈希表是通过使用称为散列法的机制来存储信息的,元素并没有以某种特定顺序来存放;
LinkedHashSet:以元素插入的顺序来维护集合的链接表,允许以插入的顺序在集合中迭代;
TreeSet:提供一个使用红黑树结构存储Set接口的实现,对象以升序顺序存储,访问和遍历的时间很快。
HashSet
HashSet有以下特点
1) 不能保证元素的排列顺序,顺序有可能发生变化
2) 不是同步的
3) 集合元素可以是null,但只能放入一个null
当向HashSet结合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据 hashCode值来决定该对象在HashSet中存储位置。
简单的说,HashSet集合判断两个元素相等的标准是两个对象通过equals方法比较相等,并且两个对象的hashCode()方法返回值相等。
注意,如果要把一个对象放入HashSet中,重写该对象对应类的equals方法,也应该重写其hashCode()方法。其规则是如果两个对象通过equals方法比较返回true时,其hashCode也应该相同。另外,对象中用作equals比较标准的属性,都应该用来计算 hashCode的值。
LinkedHashSet
LinkedHashSet集合同样是根据元素的hashCode值来决定元素的存储位置,但是它同时使用链表维护元素的次序。这样使得元素看起来像是以插入顺序保存的,也就是说,当遍历该集合时候,LinkedHashSet将会以元素的添加顺序访问集合的元素。
LinkedHashSet在迭代访问Set中的全部元素时,性能比HashSet好,但是插入时性能稍微逊色于HashSet。
TreeSet类
TreeSet是SortedSet接口的唯一实现类,TreeSet可以确保集合元素处于排序状态。TreeSet支持两种排序方式,自然排序和定制排序,其中自然排序为默认的排序方式。向TreeSet中加入的应该是同一个类的对象。
TreeSet判断两个对象不相等的方式是两个对象通过equals方法返回false,或者通过CompareTo方法比较没有返回0。
自然排序
自然排序使用要排序元素的CompareTo(Object obj)方法来比较元素之间大小关系,然后将元素按照升序排列。
Java提供了一个Comparable接口,该接口里定义了一个compareTo(Object obj)方法,该方法返回一个整数值,实现了该接口的对象就可以比较大小。
obj1.compareTo(obj2)方法如果返回0,则说明被比较的两个对象相等,如果返回一个正数,则表明obj1大于obj2,如果是负数,则表明obj1小于obj2。
如果我们将两个对象的equals方法总是返回true,则这两个对象的compareTo方法返回应该返回0
定制排序
自然排序是根据集合元素的大小,以升序排列,如果要定制排序,应该使用Comparator接口,实现 int compare(T o1,T o2)方法.
八、HashMap
1、HashMap采用数组方式存储key,value构成的Entry对象,无容量限制。
2、HashMap基于Key hash查找Entry对象存放到数组的位置,对于hash冲突采用链表的方式来解决。
3、HashMap在插入元素时可能会要扩大数组的容量,在扩大容量时须要重新计算hash,并复制对象到新的数组中。
4、HashMap是非线程安全的。
5、HashMap遍历使用的是Iterator
九、HashTable
1、HashTable是线程安全的。
2、HashTable中无论是Key,还是Value都不允许为null。
3. HashTable遍历使用的是Enumeration。
曾经HashTable的应用非常广泛,HashMap是新框架中用来代替HashTable的类,也就是说建议使用HashMap,不要使用HashTable,可以使用ConcurrentHashMap。那么几者之间有什么区别呢?
1、HashTable的内部存储结构
HashTable和HashMap采用相同的存储机制,二者的实现基本一致,不同的是:
1)、HashMap是非线程安全的,HashTable是线程安全的,内部的方法基本都是synchronized。
2)、HashTable不允许有null值的存在。
在HashTable中调用put方法时,如果key为null,直接抛出NullPointerException。其它细微的差别还有,比如初始化Entry数组的大小等等,但基本思想和HashMap一样。
2、HashTable和ConcurrentHashMap的比较
ConcurrentHashMap是目前最好的线程安全的HashMap的实现。同样是线程安全的类,它与HashTable在同步方面有什么不同呢?
HashTable使用synchronized关键字来确保同步,而Synchronized其实是对对象加锁,不论你是在方法前加synchronized还是语句块前加,锁住的都是对象整体, 但是ConcurrentHashMap的同步机制和这个不同,它不是加synchronized关键字,而是基于lock操作的,这样的目的是保证同步的时候,锁住的不是整个对象。事实上,ConcurrentHashMap可以满足concurrentLevel个线程并发无阻塞的操作集合对象。
需要特别注意的是,我们在具体的项目开发中必须对HashMap的非线程安全保持足够的关注,如果在并发场景中不保持足够的同步,就有可能在执行HashMap.get是进入死循环,将CPU耗到100%。
十、TreeMap:
1、SortMap的实现
2、TreeMap是一个典型的基于红黑树的Map实现,因此它要求一定要有Key比较的方法,要么传入Comparator实现,要么key对象实现Comparable接口。
3、TreeMap是非线程安全的。
十一、LinkedHashMap:
1. LinkedHashMap 是HashMap的一个子类,保存了记录的插入顺序,在用Iterator遍历LinkedHashMap时,先得到的记录肯定是先插入的.
2. LinkedHashMap 也可以在构造时用带参数,按照应用次数排序。
LinkedHashMap在遍历的时候会比HashMap慢。不过有种情况例外,当HashMap容量很大,实际数据较少时,遍历起来可能会比 LinkedHashMap慢,因为LinkedHashMap的遍历速度只和实际数据有关,和容量无关,而HashMap的遍历速度和他的容量有关。