List、Set、Map集合的区别以及各个集合的适用场景

目    录(本篇字数:2843)

介绍

Collection容器(接口)

AbstractList(抽象类,实现List接口)— 列表

ArrayList(直接实现类)

LinkedList(间接实现类)

Vector(直接实现类)

AbstractSet(抽象类,实现Set接口)— 集合

HashSet(直接实现类)

TreeSet(直接实现类)

LinkedHashSet(间接实现类)

Map映射(接口)

AbstractMap(抽象类,实现Map接口)— 键值对(key,value)

HashMap(直接实现类)

TreeMap(直接实现类)

WeakHashMap(直接实现类)

LinkedHashMap(间接实现类)

它们的区别

1、容器类与数组的区别

2、注意点

3 、Map 中元素,可以将 key 序列、 value 序列单独抽取出来。


  • 介绍

    掌握Java的几种集合类区别,这是学习Java的基础,也是Java开发者的必备技能了。在很多企业的面试中,可能会面试关于这个类型的问题,比如Java几种集合的区别。那么,本篇文章将带你理解Java各个集合的主要区别。

  • Collection容器(接口)

  • AbstractList(抽象类,实现List接口)— 列表

    List(列表)的特点是:元素是有序的、允许有任意个重复元素,包括空元素。

  • ArrayList(直接实现类)

    ArrayList:线程不同步的数组列表。它以数组的方式实现了一个列表,它的设计导致它拥有迅速的遍历元素的手段。在同样庞大的数据量面前,它的遍历元素的速度是LinkedList无法比较的。既然遍历元素的区别这么庞大,那么为了让大家眼见为实,我特意写了这么一个例子,用这两个集合去遍历同样是10万条字符串的数据。下面看看它的区别吧!(官方原文说明:这个类相当于Vector类,只是线程是不同步的)

    ArrayList,遍历100万条字符串数据耗时记录(ArrayList遍历元素所用的时间:平均数:2651.4ms / 单位ms)

    LinkedList,遍历10万条字符串数据耗时记录(LinkedList遍历元素所用的时间:平均:19070.3ms / 单位ms),我测试过在遍历100万条时,已经出现内存溢出的现象,界面无响应。

  • LinkedList(间接实现类)

    LinkedList:也是线程不同步的列表,但是它是通过链表的方式实现的。既然是通过链表的方式,那么它在储存元素的位置上就做了非常多的工作量。它的设计导致它可以像链表一样,提供了最佳的顺序存储元素手段。它与ArrayList的区别就是:LinkedList通常用于对顺序位置要求高、增、删操作频繁的场景中。而ArrayList主要运用于对元素的遍历操作,不太需要增、删操作的场景。

  • Vector(直接实现类)

    Vector:是线程同步的。官方对它的介绍是:Vector类实现了一个可增长的对象数组。与数组一样,它包含可以使用整数索引访问的组件。然而,向量的大小可以根据需要增加或减少,以适应在创建向量之后添加和删除项。

    当一个 Iterator 被创建而且正在被使用,另一个线程改变了 Vector 的状态(例如,添加或删除了一些元素),这时调用 Iterator 的方法时将抛出 ConcurrentModificationException ,因此必须捕获该异常。

  • AbstractSet(抽象类,实现Set接口)— 集合

    Set(集合)的特点是:元素是无序的、不允许重复元素,有且仅有一个空元素存在。

  • HashSet(直接实现类)

    HashSet:是线程不同步的,如果多个线程并发地访问哈希集,并且至少有一个线程修改了这个集,那么它必须在外部同步。它不保证集合的迭代顺序,特别地,它不能保证顺序会随时间保持不变。该类允许空元素。

  • TreeSet(直接实现类)

    TreeSet:是线程不同步的,它基于TreeMap的NavigableSet实现,使得元素使用它们的自然顺序进行排序。保证元素唯一性的方式,通过比较的结果是否为0。底层数据结构是:二叉树。

  • LinkedHashSet(间接实现类)

    LinkedHashSet:哈希表和链表实现的集合接口,具有可预测的迭代顺序。这个实现与HashSet不同之处在于它维护一个遍历其所有条目的双链链表。这个链表定义了迭代顺序,这是元素插入到集合中的顺序(插入顺序)。注意,如果一个元素被重新插入到集合中,插入顺序不会受到影响(如果当.contains(e)在调用之前立即返回true时调用s.add(e),则元素e被重新插入到集合s中)。

    这个实现使它的客户端免受HashSet提供的未指定的、通常是混乱的排序的影响,而不会增加与TreeSet相关的成本。它可以用于生成与原始集合具有相同顺序的集合的副本,而不考虑原始集合的实现:

  • Map映射(接口)

  • AbstractMap(抽象类,实现Map接口)— 键值对(key,value)

    将键映射到值的对象。不能包含重复的键,每个键最多可以映射到一个值,也就是说有且仅有一个键。当然,键可以为空值,但必须仅存有一个,而值可以是任意个数的空值。

  • HashMap(直接实现类)

    基于哈希表实现的映射接口。这个实现提供了所有可选的映射操作,并允许空值和空键。(HashMap类大致相当于Hashtable,但它是非同步的,并且允许为空)。这个类不保证映射的顺序;特别地,它不能保证顺序会随时间保持不变。

  • TreeMap(直接实现类)

    一种基于红黑树的NavigableMap实现,元素是按自然顺序排列的,也是非同步的。

  • WeakHashMap(直接实现类)

    基于哈希表实现的映射接口,带有弱键。当WeakHashMap的键不再正常使用时,它的条目将被自动删除。当一个键被丢弃时,它的条目将有效地从映射中删除,因此这个类的行为与其他映射实现有些不同。支持空值和空键。该类具有与HashMap类相似的性能特征,也是非同步的。

  • LinkedHashMap(间接实现类)

    哈希表和链表实现的映射接口,具有可预测的迭代顺序。这个实现与HashMap不同之处在于,它维护一个遍历其所有条目的双链接列表。这个链表定义了迭代顺序,这通常是键插入到映射中的顺序(插入顺序)。

  • 它们的区别

    我们只要大致的能理解这些区别就可以了,下面来总结一下这几个集合的使用场景和其他的一些区别:

1、容器类与数组的区别

    容器类仅能持有对象引用(指向对象的指针),而不是将对象信息 copy 一份至数列某位置。一旦将对象置入容器内,便损失了该对象的型别信息。

    Collection 、List 、Set 、Map 都是接口,不能实例化。 ArrayList, Vector, HashTable, HashMap 是具体类,这些才可被实例化。这就是我们为什么 List list = new ArrayList();的原因所在。

2、注意点

    (1) 、 Collection 只能通过 iterator() 遍历元素,没有 get() 方法来取得某个元素。

    (2) 、 Set 和 Collection 拥有一模一样的接口。但排除掉传入的 Collection 参数重复的元素。

    (3) 、 List 可以通过 get() 方法来一次取出一个元素。使用数字下标来选择一堆对象中的一个,例如: get(0),取第一个。

    (4) 、 Map 用 put(k,v) / get(k) ,还可以使用 containsKey()/containsValue() 来检查其中是否含有某个 key/value 。

    HashMap 会利用对象的 hashCode 来快速找到 key 。

    哈希码 (hashing) 就是将对象的信息经过一些转变形成一个独一无二的 int 值,这个值存储在一个 array 中。我们都知道所有存储结构中, array 查找速度是最快的。所以,可以加速查找。发生碰撞时,让 array 指向多个 values 。即,数组每个位置上又生成一个梿表。

3 、Map 中元素,可以将 key 序列、 value 序列单独抽取出来。

    使用 keySet() 抽取 key 序列,将 map 中的所有 keys 生成一个 Set 。

    使用 values() 抽取 value 序列,将 map 中的所有 values 生成一个 Collection 。

    为什么一个生成 Set ,一个生成 Collection ? 那是因为, key 总是独一无二的, value 允许重复。

    (1)、在各种 Lists ,对于需要快速插入,删除元素,应该使用 LinkedList (可用 LinkedList 构造堆栈 stack 、队列 queue ),如果需要快速随机访问元素,应该使用 ArrayList 。最好的做法是以 ArrayList 作为缺省选择。 Vector 总是比 ArrayList 慢,所以要尽量避免使用。

    (2)、在各种 Sets 中, HashSet 通常优于 HashTree (插入、查找)。只有当需要产生一个经过排序的序列,才用 TreeSet 。 HashTree 存在的唯一理由:能够维护其内元素的排序状态。

    (3)、在各种 Maps 中 HashMap 用于快速查找。最后,当元素个数固定,用 Array ,因为 Array 效率是最高的。

    (4)、 如果程序在单线程环境中,或者访问仅仅在一个线程中进行,考虑非同步的类,其效率较高,如果多个线程可能同时操作一个类,应该使用同步的类。 
    (5)、 要特别注意对哈希表的操作,作为 key 的对象要同时正确复写 equals 方法和 hashCode 方法。 
尽量返回接口而非实际的类型,如返回 List 而非 ArrayList ,这样如果以后需要将 ArrayList 换成 LinkedList 时,客户端代码不用改变。这就是针对抽象编程。

©原文链接:https://blog.csdn.net/smile_running/article/details/81113561

@作者博客:_Xu2WeI

@更多博文:查看作者的更多博文

posted @ 2018-07-19 13:21  爱写Bug的程序猿  阅读(1258)  评论(0编辑  收藏  举报