java集合

java集合

集合之间的关系

Collection
├List
│├LinkedList
│├ArrayList
│└Vector
│ └Stack
└Set
Map
├Hashtable
├HashMap
└WeakHashMap

Collection

最基本的集合接口,一个Collection代表一组Object的集合,这些Object被称作Collection的元素。Collection是一个接口,用以提供规范定义,不能被实例化使用;不论 Collection 的实际类型如何,它都支持一个 iterator() 的方法,该方法返回一个迭代子,使用该迭代子即可逐一访问 Collection 中每一个元素。典型的用法如下:
Iterator it = collection.iterator(); // 获得一个迭代子
while(it.hasNext()){
Object obj = it.next(); // 得到下一个元素
}

List

List集合代表一个元素有序、可重复的集合,集合中每个元素都有其对应的顺序索引。List集合允许加入重复元素,因为它可以通过索引来访问指定位置的集合元素。List集合默认按元素的添加顺序设置元素的索引,除了具有 Collection 接口必备的 iterator() 方法外,List 还提供一个 listIterator() 方法,返回一个 ListIterator 接口。和标准的 Iterator 接口相比,ListIterator 多了一些 add() 之类的方法,允许添加、删除、设定元素、向前或向后遍历等功能,实现 List 接口的常用类有 LinkedList,ArrayList,Vector 和 Stack

LinkedList

LinkedList 实现了 List 接口,允许 Null 元素。此外 LinkedList 提供额外的 Get、Remove、Insert 等方法在 LinkedList 的首部或尾部操作数据。这些操作使得 LinkedList 可被用作堆栈(Stack)、队列(Queue)或双向队列(Deque,无同步方法,创建 List 时构造一个同步的 List,方法如
List list = Collections.synchronizedList(new LinkedList(...))

ArrayList

ArrayList是基于数组实现的List类,它封装了一个动态的增长的、允许再分配的Object[]数组,它允许所有元素,包括 Null。Size、IsEmpty、Get、Set 等方法的运行时间为常数,但是 Add 方法开销为分摊的常数,添加 N 个元素需要 O(N) 的时间,其他的方法运行时间为线性,也是非线程同步的,另外在插入大量元素时可以调用 ensureCapacity 方法来增加 ArrayList 的容量以提高插入效率

Vector

和ArrayList基本一致,但是是线程同步,同时使用时可能会抛出ConcurrentModificationException,因此必须捕获该异常

Stack

Stack 继承自 Vector,实现了一个后进先出的堆栈。Stack 提供 5 个额外的方法使得 Vector 得以被当作堆栈使用。除了基本的 Push 和 Pop 方法,还有 Peek 方法得到栈顶的元素,Empty 方法测试堆栈是否为空,Search 方法检测一个元素在堆栈中的位置。注意,Stack 刚创建后是空栈

Set

Set 是一种不包含重复的元素的 Collection,即任意的两个元素 e1 和 e2 都有 e1.equals(e2)=false。Set 最多有一个 null 元素。很明显,Set 的构造函数有一个约束条件,传入的 Collection 参数不能包含重复的元素。请注意,必须小心操作可变对象(Mutable Object),如果一个 Set 中的可变元素改变了自身状态,这可能会导致一些问题,另外:Set判断两个对象相同不是使用"=="运算符,而是根据equals方法。

HashSet

HashSet是Set接口的典型实现,HashSet使用HASH算法来存储集合中的元素,因此具有良好的存取和查找性能。
当向HashSet集合中存入一个元素时,HashSet会调用该对象的hashCode()方法来得到该对象的hashCode值,然后根据该HashCode值决定该对象在HashSet中的存储位置。
值得注意的是,HashSet集合判断两个元素相等的标准是两个对象通过equals()方法比较相等,并且两个对象的hashCode()方法的返回值相等

LinkedHashSet

LinkedHashSet集合也是根据元素的hashCode值来决定元素的存储位置,但和HashSet不同的是,它同时使用链表维护元素的次序,这样使得元素看起来是以插入的顺序保存的。
当遍历LinkedHashSet集合里的元素时,LinkedHashSet将会按元素的添加顺序来访问集合里的元素。
LinkedHashSet需要维护元素的插入顺序,因此性能略低于HashSet的性能,但在迭代访问Set里的全部元素时(遍历)将有很好的性能(链表很适合进行遍历)

SortedSet

此接口主要用于排序操作,即实现此接口的子类都属于排序的子类

TreeSet

TreeSet是SortedSet接口的实现类,TreeSet可以确保集合元素处于排序状态

Map

Map用于保存具有"映射关系"的数据,因此Map集合里保存着两组值,一组值用于保存Map里的key,另外一组值用于保存Map里的value。key和value都可以是任何引用类型的数据。Map的key不允许重复,即同一个Map对象的任何两个key通过equals方法比较结果总是返回false。关于Map,我们要从代码复用的角度去理解,java是先实现了Map,然后通过包装了一个所有value都为null的Map就实现了Set集合,Map的这些实现类和子接口中key集的存储形式和Set集合完全相同(即key不能重复),Map的这些实现类和子接口中value集的存储形式和List非常类似(即value可以重复、根据索引来查找)

HashMap

和HashSet集合不能保证元素的顺序一样,HashMap也不能保证key-value对的顺序。并且类似于HashSet判断两个key是否相等的标准也是: 两个key通过equals()方法比较返回true;同时两个key的hashCode值也必须相等;如果迭代操作的性能相当重要的话,不要将 HashMap 的初始化容量设得过高,或者 Load Factor 参数设置过低。

LinkedHashMap

LinkedHashMap也使用双向链表来维护key-value对的次序,该链表负责维护Map的迭代顺序,与key-value对的插入顺序一致(注意和TreeMap对所有的key-value进行排序进行区

Hashtable

是一个古老的Map实现类,线程同步,Hashtable 继承 Map 接口,实现了一个基于 Key-Value 映射的哈希表。任何非空(non-null)的对象都可作为 Key 或者 Value。添加数据使用 Put(Key,Value),取出数据使用 Get(Key),这两个基本操作的时间开销为常数,Hashtable 通过 Initial Capacity 和 Load Factor 两个参数调整性能。通常缺省的 Load Factor 0.75 较好地实现了时间和空间的均衡。增大 Load Factor 可以节省空间但相应的查找时间将增大,会影响像 Get 和 Put 这样的操作

TreeMap

TreeMap就是一个红黑树数据结构,每个key-value对即作为红黑树的一个节点。TreeMap存储key-value对(节点)时,需要根据key对节点进行排序。TreeMap可以保证所有的key-value对处于有序状态。同样,TreeMap也有两种排序方式: 自然排序、定制排序

WeakHashMap

WeakHashMap与HashMap的用法基本相似。区别在于,HashMap的key保留了对实际对象的"强引用",这意味着只要该HashMap对象不被销毁,该HashMap所引用的对象就不会被垃圾回收。但WeakHashMap的key只保留了对实际对象的弱引用,这意味着如果WeakHashMap对象的key所引用的对象没有被其他强引用变量所引用,则这些key所引用的对象可能被垃圾回收,当垃圾回收了该key所对应的实际对象之后,WeakHashMap也可能自动删除这些key所对应的key-value对。

实践

ArrayList、Vector、LinkedList 均来自 AbstractList 的实现,而 AbstractList 直接实现了 List 接口,并扩展自 AbstarctCollection。ArrayList 和 Vector 使用了数组实现,ArrayList 没有对任何一个方法提供线程同步,因此不是线程安全的,Vector 中绝大部分方法都做了线程同步,是一种线程安全的实现。LinkedList 使用了循环双向链表数据结构,由一系列表项连接而成,一个表项总是包含 3 个部分,元素内容、前驱表项和后驱表项。
当 ArrayList 对容量的需求超过当前数组的大小时,需要进行扩容。扩容过程中,会进行大量的数组复制操作,而数组复制时,最终将调用 System.arraycopy() 方法。LinkedList 由于使用了链表的结构,因此不需要维护容量的大小,然而每次的元素增加都需要新建一个 Entry 对象,并进行更多的赋值操作,在频繁的系统调用下,对性能会产生一定的影响,在不间断地生成新的对象还是占用了一定的资源。而因为数组的连续性,因此总是在尾端增加元素时,只有在空间不足时才产生数组扩容和数组复制。
ArrayList 是基于数组实现的,而数组是一块连续的内存空间,如果在数组的任意位置插入元素,必然导致在该位置后的所有元素需要重新排列,因此其效率较差,尽可能将数据插入到尾部。LinkedList 不会因为插入数据导致性能下降。
ArrayList 的每一次有效的元素删除操作后都要进行数组的重组,并且删除的元素位置越靠前,数组重组时的开销越大,要删除的元素位置越靠后,开销越小。LinkedList 要移除中间的数据需要便利完半个 List。
HashMap 是将 Key 做 Hash 算法,然后将 Hash 值映射到内存地址,直接取得 Key 所对应的数据。在 HashMap 中,底层数据结构使用的是数组,所谓的内存地址即数组的下标索引。HashMap 的高性能需要保证以下几点:

  1. Hash 算法必须是高效的;
  2. Hash 值到内存地址 (数组索引) 的算法是快速的;
  3. 根据内存地址 (数组索引) 可以直接取得对应的值。

HashMap 实际上是一个链表的数组。前面已经介绍过,基于 HashMap 的链表方式实现机制,只要 HashCode() 和 Hash() 方法实现得足够好,能够尽可能地减少冲突的产生,那么对 HashMap 的操作几乎等价于对数组的随机访问操作,具有很好的性能。但是,如果 HashCode() 或者 Hash() 方法实现较差,在大量冲突产生的情况下,HashMap 事实上就退化为几个链表,对 HashMap 的操作等价于遍历链表,此时性能很差。
HashMap 的一个功能缺点是它的无序性,被存入到 HashMap 中的元素,在遍历 HashMap 时,其输出是无序的。如果希望元素保持输入的顺序,可以使用 LinkedHashMap 替代。
LinkedHashMap 继承自 HashMap,具有高效性,同时在 HashMap 的基础上,又在内部增加了一个链表,用以存放元素的顺序。
HashMap 通过 hash 算法可以最快速地进行 Put() 和 Get() 操作。TreeMap 则提供了一种完全不同的 Map 实现。从功能上讲,TreeMap 有着比 HashMap 更为强大的功能,它实现了 SortedMap 接口,这意味着它可以对元素进行排序。TreeMap 的性能略微低于 HashMap。如果在开发中需要对元素进行排序,那么使用 HashMap 便无法实现这种功能,使用 TreeMap 的迭代输出将会以元素顺序进行。LinkedHashMap 是基于元素进入集合的顺序或者被访问的先后顺序排序,TreeMap 则是基于元素的固有顺序 (由 Comparator 或者 Comparable 确定)。
LinkedHashMap 是根据元素增加或者访问的先后顺序进行排序,而 TreeMap 则根据元素的 Key 进行排序。

总结

综合前面的介绍,我们可以知道,如果涉及到堆栈、队列等操作,应该考虑用 List。对于需要快速插入、删除元素等操作,应该使用 LinkedList。如果需要快速随机访问元素,应该使用 ArrayList。如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高。如果多个线程可能同时操作一个类,应该使用同步的类。要特别注意对哈希表的操作,作为 Key 的对象要正确复写 Equals 和 HashCode 方法。尽量返回接口而非实际的类型,如返回 List 而非 ArrayList,这样如果以后需要将 ArrayList 换成 LinkedList 时,客户端代码不用改变,这就是针对抽象进行编程思想

整理自:
http://www.ibm.com/developerworks/cn/java/j-lo-set-operation/index.html
http://www.cnblogs.com/LittleHann/p/3690187.html
http://wiki.jikexueyuan.com/project/java-interview-bible/collection.html
http://www.importnew.com/13801.html

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,701评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,649评论 3 396
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 166,037评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,994评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 68,018评论 6 395
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,796评论 1 308
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,481评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,370评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,868评论 1 319
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 38,014评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,153评论 1 352
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,832评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,494评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,039评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,156评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,437评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,131评论 2 356

推荐阅读更多精彩内容

  • title: java集合框架学习总结 tags:集合框架 categories:总结 date: 2017-03...
    行径行阅读 1,689评论 0 2
  • 3.3 集合 一方面, 面向对象语言对事物的体现都是以对象的形式,为了方便对多个对象的操作,就要对对象进行存储。另...
    闫子扬阅读 728评论 0 1
  • Collection & Map Collection 子类有 List 和 Set List --> Array...
    任教主来也阅读 3,164评论 1 9
  • 以下是《疯狂Java讲义》中的一些知识,如有错误,烦请指正。 集合概述 Java集合可以分为Set、List、Ma...
    hainingwyx阅读 540评论 0 1
  • 高考是青春的一个元素,一个标志,一个里程碑,是十年寒窗的全部意义。 昨天是高考的第一天...
    西雅图夜雨阅读 512评论 4 3