【问题标题】:Difference between HashMap, LinkedHashMap and TreeMapHashMap、LinkedHashMap、TreeMap的区别
【发布时间】:2011-02-22 19:17:51
【问题描述】:

HashMapLinkedHashMapTreeMap 在 Java 中的区别是什么? 我看不出输出有任何区别,因为这三个都有keySetvaluesHashtables 是什么?

Map m1 = new HashMap();
m1.put("map", "HashMap");
m1.put("schildt", "java2");
m1.put("mathew", "Hyden");
m1.put("schildt", "java2s");
print(m1.keySet()); 
print(m1.values()); 

SortedMap sm = new TreeMap();
sm.put("map", "TreeMap");
sm.put("schildt", "java2");
sm.put("mathew", "Hyden");
sm.put("schildt", "java2s");
print(sm.keySet()); 
print(sm.values());

LinkedHashMap lm = new LinkedHashMap();
lm.put("map", "LinkedHashMap");
lm.put("schildt", "java2");
lm.put("mathew", "Hyden");
lm.put("schildt", "java2s");
print(lm.keySet()); 
print(lm.values());

【问题讨论】:

    标签: java map


    【解决方案1】:

    我更喜欢视觉呈现:

    Property HashMap TreeMap LinkedHashMap
    Iteration Order no guaranteed order, will remain constant over time sorted according to the natural ordering insertion-order
    Get / put / remove / containsKey O(1) O(log(n)) O(1)
    Interfaces Map NavigableMap, Map, SortedMap Map
    Null values/keys allowed only values allowed
    Fail-fast behavior Fail-fast behavior of an iterator cannot be guaranteed, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification Fail-fast behavior of an iterator cannot be guaranteed, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification Fail-fast behavior of an iterator cannot be guaranteed, impossible to make any hard guarantees in the presence of unsynchronized concurrent modification
    Implementation buckets Red-Black Tree double-linked buckets
    Is synchronized implementation is not synchronized implementation is not synchronized implementation is not synchronized

    【讨论】:

    • 除了插入顺序,LinkedHashMap还支持访问顺序(当使用带有布尔访问顺序参数的构造函数时)。
    • 双链接桶?我认为这增加了搜索存储桶以进行插入/删除操作的不必要开销(因为它必须搜索正确的存储桶才能放入对象)。我一直认为 LinkedHashMap 的实现与 Map 的实现类似,但用于迭代目的的“条目列表”(可能作为链表)有一点额外的开销。你确定吗,舍甫奇克?如果是,你能解释一下或给我一些支持你的说法的在线链接吗?
    • @SaiDubbaka LinkedHashMap 有双链接桶,但桶表 HashMap 也有。它不会取代它。这意味着访问存储桶的方式与在 HashMap 中相同,因为链表仅用于按插入顺序(或访问顺序)进行迭代。
    • 值得一提的是,O(1) 是最好的情况(我们通常不会称之为 O,参见this question
    • 另外值得注意的是,O(1) 并不总是比 O(log n) 好;如果你有一个很长的密钥,那么基于 BST 的东西可能比必须对整个密钥执行 O(n) 哈希才能执行任何操作的东西快得多。
    【解决方案2】:

    所有三个类都实现了Map 接口,并提供了几乎相同的功能。最重要的区别是条目的迭代顺序:

    • HashMap 绝对不保证迭代顺序。当添加新元素时,它甚至可以(并且将会)完全改变。
    • TreeMap 将根据它们的 compareTo() 方法(或外部提供的 Comparator)根据键的“自然顺序”进行迭代。此外,它还实现了SortedMap 接口,其中包含依赖于这种排序顺序的方法。
    • LinkedHashMap 将按照条目放入地图的顺序进行迭代

    "Hashtable" 是基于哈希的映射的通用名称。在 Java API 的上下文中, Hashtable 是集合框架存在之前的 Java 1.1 时代的一个过时类。不应再使用它,因为它的 API 中充斥着重复功能的过时方法,并且它的方法是同步的(这会降低性能并且通常是无用的)。使用ConcurrentHashMap 而不是哈希表。

    【讨论】:

    • Map到底是什么,Map、HashMap和Hashtables有什么区别。
    • @theband:地图是一个接口。 HashMap 和 Hashtable 都实现了它;正如我所写,Hashtable 是一个遗留类。
    • HashtableHashMap 之间的一个显着区别在于,在哈希表中,“键和值都不能为空”。后者不存在此约束。
    • @AshkanN:是的——事实上这些是实现排序的标准方法。 TreeMap 有一个使用 Comparator 的构造函数,如果没有提供,它期望添加的所有对象都实现 Comparable。
    • 您可以选择是否要按插入顺序或访问顺序进行 LinkedHashMap 迭代。
    【解决方案3】:

    这三个都表示从唯一键到值的映射,因此实现了Map 接口。

    1. HashMap 是基于hashing 的键的映射。它支持 O(1) 获取/放置操作。密钥必须有 consistent implementations of hashCode() and equals() 才能工作。

    2. LinkedHashMap 与 HashMap 非常相似,但它增加了对添加(或访问)项的顺序的感知,因此迭代顺序与插入顺序(或访问顺序,取决于构造参数)相同.

    3. TreeMap 是基于树的映射。它的 put/get 操作需要 O(log n) 时间。它要求项目具有某种比较机制,无论是 Comparable 还是 Comparator。迭代顺序由该机制决定。

    【讨论】:

    • 所以如果我理解正确的话,LinkedHashMap 和 TreeMap 之间的唯一区别是性能,因为插入顺序与自然顺序相同?
    • @MosheShaham 正如他在#2 中所说:LinkedHashMap 将按插入顺序而不是自然顺序进行迭代。因此,如果您将(2,5,3) 添加到LinkedHashMap 并对其执行每个操作,它将返回2,5,3。如果是 2,5,3TreeMap,它将返回 2,3,5
    • 树形图还有很多其他不错的技巧。比如头尾图。
    • 私有 TreeMap mySection2 = new TreeMap(); mySection2.put("abc1", 2); mySection2.put("abc2",5); mySection2.put("abc3",3); for(整数 x : mySection2.values()) { Log.e("LOG","TreeMap===="+x);这给了我与插入项目相同的顺序?请建议它与 LinkedHashMaps 有何不同?
    • @B.shruti:这是因为您的插入顺序与您的键的字典顺序相匹配(“abc1”、“abc2”、“abc3”)。如果您以不同的顺序插入,您的代码仍将根据字典顺序进行迭代。
    【解决方案4】:

    在下图中查看每个类在类层次结构中的位置 (bigger one)。 TreeMap 实现了SortedMapNavigableMap,而HashMap 没有。

    HashTable 已过时,应使用相应的 ConcurrentHashMap 类。

    【讨论】:

    • 这张图的答案太棒了
    【解决方案5】:

    哈希映射

    • 它有对值(键,值)
    • 没有重复的键值
    • 无序无序
    • 它允许一个空键和多个空值

    哈希表

    • 与哈希映射相同
    • 它不允许空键和空值

    LinkedHashMap

    • 是有序版的地图实现
    • 基于链表和散列数据结构

    树状图

    • 有序和分类版本
    • 基于散列数据结构

    【讨论】:

    • HashTable 也是同步的。无论如何,我喜欢你的回答,简洁明了。
    【解决方案6】:

    从我自己的地图经验中获得更多信息,关于我何时使用每个地图:

    • HashMap - 在寻找最佳性能(快速)实现时最有用。
    • TreeMap(SortedMap 接口)- 当我关心能够以我定义的特定顺序对键进行排序或迭代时最有用。
    • LinkedHashMap - 结合了从 TreeMap 保证排序的优点,而不会增加维护 TreeMap 的成本。 (它几乎和 HashMap 一样快)。特别是,LinkedHashMap 还通过覆盖removeEldestEntry() 方法为创建缓存对象提供了一个很好的起点。这使您可以创建一个 Cache 对象,该对象可以使用您定义的某些条件使数据过期。

    【讨论】:

    • 确切地说,TreeMap 并没有保持元素的顺序。它使键保持有序。
    【解决方案7】:

    HashMapTreeMapLinkedHashMap 这三个类都实现了java.util.Map 接口,表示从唯一键到值的映射。

    HashMap

    1. HashMap 包含基于键的值。

    2. 它只包含独特的元素。

    3. 它可能有一个空键和多个空值。

    4. 它维持无序

      public class HashMap<K,V> extends AbstractMap<K,V> implements Map<K,V>, Cloneable, Serializable

    LinkedHashMap

    1. LinkedHashMap 包含基于键的值。
    2. 它只包含独特的元素。
    3. 它可能有一个空键和多个空值。
    4. 与HashMap相同,而是维护插入顺序//见下面的类减速

      public class LinkedHashMap<K,V> extends HashMap<K,V> implements Map<K,V>

    TreeMap

    1. TreeMap 包含基于键的值。它实现了 NavigableMap 接口并扩展了 AbstractMap 类。
    2. 它只包含独特的元素。
    3. 它不能有空键,但可以有多个空值。
    4. 它与HashMap 相同,而是保持升序(使用其键的自然顺序排序。)。

      public class TreeMap<K,V> extends AbstractMap<K,V> implements NavigableMap<K,V>, Cloneable, Serializable

    Hashtable

    1. Hashtable 是一个列表数组。每个列表称为一个桶。通过调用 hashcode() 方法来识别桶的位置。 Hashtable 包含基于键的值。
    2. 它只包含独特的元素。
    3. 它可能没有任何空键或空值。
    4. 它是同步的
    5. 这是一个遗留类。

      public class Hashtable<K,V> extends Dictionary<K,V> implements Map<K,V>, Cloneable, Serializable

    参考:http://javarevisited.blogspot.in/2015/08/difference-between-HashMap-vs-TreeMap-vs-LinkedHashMap-Java.html

    【讨论】:

    • HashMap 的大 O 表示法不应为 O(1)。这是 best 的情况,而哈希表的最坏情况是 O(n)。您的链接支持这一点。
    • @HaakonLøtveit 我还建议在这里获取实际代码 - grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
    • 这仍然说在最坏的情况下它是 O(n)。这是一个数学概念,你不能说它是 O(1),除非它实际上是 O(1)。您还在这里假设了一些非常好的散列函数。我的意思是,我们可以使用类似的东西 class TerribleHashKey { @Override hashCode() { return 4; /* 由公平掷骰子决定 */ }} 并将其用作其他有趣事物的键。具有 O(1) 的高概率和具有 O(1) 的概率是不一样的。人们来这里寻求家庭作业的帮助。让我们不要毁了他们的成绩.. ;)
    • 值得注意的是,在 Java 8 中,如果您有超过 8 个存储桶,则最坏的情况是 O(log(n)),有关详细信息,请参阅 grepcode.com/file/repository.grepcode.com/java/root/jdk/openjdk/…
    【解决方案8】:

    HashMap 绝对不保证迭代顺序。它 当添加新元素时,甚至可以(并且将会)完全改变。 TreeMap 将根据键的“自然顺序”进行迭代 根据他们的 compareTo() 方法(或外部提供的 比较器)。此外,它还实现了 SortedMap 接口, 其中包含依赖于这种排序顺序的方法。 LinkedHashMap 将按照条目放入地图的顺序进行迭代

    看看性能如何变化..

    树图是排序图的一种实现。由于自然排序,put、get 和 containsKey 操作的复杂度为 O(log n)

    【讨论】:

    • 谢谢,LinkedHashMap 的“维护订单的 O(1) 费用”是有道理的,但你有没有参考更详细的解释?
    【解决方案9】:

    @Amit:SortedMap 是一个接口,而TreeMap 是一个实现SortedMap 接口的类。这意味着 if 遵循SortedMap 要求其实现者执行的协议。 除非实现为搜索树,否则树无法为您提供有序数据,因为树可以是任何类型的树。因此,为了使 TreeMap 像 Sorted order 一样工作,它实现了 SortedMap(例如,二叉搜索树 - BST,平衡 BST,如 AVL 和 R-B 树,甚至三叉搜索树 - 主要用于以有序方式进行迭代搜索)。

    public class TreeMap<K,V>
    extends AbstractMap<K,V>
    implements SortedMap<K,V>, Cloneable, Serializable
    

    在坚果壳中 HashMap :在 O(1) 中给出数据,没有排序

    TreeMap : 给出 O(log N) 中的数据,以 2 为基数。带有有序键

    LinkedHashMap : 是具有链表(想想 indexed-SkipList)能力的哈希表,以插入树的方式存储数据。最适合实现 LRU(最近最少使用)。

    【讨论】:

      【解决方案10】:

      哈希映射不保留插入顺序。
      例子。哈希图 如果您将键插入为

      1  3
      5  9
      4   6
      7   15
      3   10
      

      它可以存储为

      4  6
      5  9
      3  10
      1  3
      7  15
      

      Linked Hashmap 保留插入顺序。

      示例。
      如果您要插入密钥

      1  3
      5  9
      4   6
      7   15
      3   10
      

      它会将其存储为

      1  3
      5  9
      4   6
      7   15
      3   10
      

      和我们插入的一样。

      树图以递增的键顺序存储值。 示例。
      如果您要插入密钥

      1  3
      5  9
      4   6
      7   15
      3   10
      

      它会将其存储为

      1  3
      3  10
      4   6
      5   9
      7   15
      

      【讨论】:

        【解决方案11】:

        HashMap 和 TreeMap 的主要区别如下

        1. HashMap 不维护任何顺序。换句话说,HashMap 不保证先插入的元素会先打印出来,就像 TreeSet 一样,TreeMap 元素也是按照其元素的自然顺序排序的

        2. 内部HashMap实现使用Hashing,TreeMap内部使用Red-Black树实现。

        3. HashMap 可以存储一个空键和多个空值。TreeMap 不能包含空键,但可以包含多个空值。

        4. HashMap 对 get 和 put 等基本操作采取恒定的时间性能,即 O(1)。根据 Oracle 文档,TreeMap 为 get 和 put 方法提供有保证的 log(n) 时间成本。

        5. HashMap 比 TreeMap 快得多,因为对于大多数操作而言,HashMap 的执行时间相对于 TreeMap 的日志时间是恒定的。

        6. HashMap 使用 equals() 方法进行比较,而 TreeMap 使用 compareTo() 方法维护排序。

        7. HashMap实现Map接口,TreeMap实现NavigableMap接口。

        【讨论】:

          【解决方案12】:

          这些是同一接口的不同实现。每种实现都有一些优点和一些缺点(插入速度快,搜索速度慢),反之亦然。

          详情请看TreeMapHashMapLinkedHashMap的javadoc。

          【讨论】:

          • Hashtables 实际上是什么以及它与 Map 的不同之处。
          【解决方案13】:
          • 哈希映射:

            • 订单不维护
            • 比 LinkedHashMap 快
            • 用于存储对象堆
          • LinkedHashMap:

            • LinkedHashMap 插入顺序将保持不变
            • 比HashMap慢,比TreeMap快
            • 如果您想维护广告订单,请使用此功能。
          • 树图:

            • TreeMap 是基于树的映射
            • TreeMap 将遵循键的自然顺序
            • 比 HashMap 和 LinkedHashMap 慢
            • 当您需要保持自然(默认)排序时使用 TreeMap

          【讨论】:

            【解决方案14】:

            这三个中最重要的是它们如何保存条目的顺序。

            HashMap - 不保存条目的顺序。 例如。

            public static void main(String[] args){
                    HashMap<String,Integer> hashMap = new HashMap<>();
                    hashMap.put("First",1);// First ---> 1 is put first in the map
                    hashMap.put("Second",2);//Second ---> 2 is put second in the map
                    hashMap.put("Third",3); // Third--->3 is put third in the map
                    for(Map.Entry<String,Integer> entry : hashMap.entrySet())
                    {
                        System.out.println(entry.getKey()+"--->"+entry.getValue());
                    }
                }
            

            LinkedHashMap :它保存输入的顺序。例如:

            public static void main(String[] args){
                    LinkedHashMap<String,Integer> linkedHashMap = new LinkedHashMap<>();
                    linkedHashMap.put("First",1);// First ---> 1 is put first in the map
                    linkedHashMap.put("Second",2);//Second ---> 2 is put second in the map
                    linkedHashMap.put("Third",3); // Third--->3 is put third in the map
                    for(Map.Entry<String,Integer> entry : linkedHashMap.entrySet())
                    {
                        System.out.println(entry.getKey()+"--->"+entry.getValue());
                    }
                }
            

            TreeMap :它以键的升序保存条目。例如:

            public static void main(String[] args) throws IOException {
                    TreeMap<String,Integer> treeMap = new TreeMap<>();
                    treeMap.put("A",1);// A---> 1 is put first in the map
                    treeMap.put("C",2);//C---> 2 is put second in the map
                    treeMap.put("B",3); //B--->3 is put third in the map
                    for(Map.Entry<String,Integer> entry : treeMap.entrySet())
                    {
                        System.out.println(entry.getKey()+"--->"+entry.getValue());
                    }
                }
            

            【讨论】:

              【解决方案15】:

              虽然这里有很多优秀的答案,但我想展示我自己的表格,描述与 Java 11 捆绑在一起的各种 Map 实现。

              我们可以在表格图形中看到这些差异:

              • HashMap通用 Map,当您没有特殊需求时常用。
              • LinkedHashMap 扩展 HashMap,添加了以下行为:维护一个顺序,最初添加条目的顺序。更改键值输入的值不会改变其在顺序中的位置。
              • TreeMap 也维护一个顺序,但使用 (a) “自然”顺序,这意味着在 Comparable 接口上定义的关键对象上的 compareTo 方法的值,或者 ( b) 调用您提供的Comparator 实现
              • NULLs:TreeMap不允许允许 NULL 作为键,而 HashMap & LinkedHashMap 允许。
                • 这三个都允许 NULL 作为值。
              • HashTablelegacy,来自 Java 1。被ConcurrentHashMap 类取代。引用 Javadoc:ConcurrentHashMap 遵循与Hashtable 相同的功能规范,并包含与Hashtable 的每个方法对应的方法版本。

              【讨论】:

                【解决方案16】:

                所有都提供了一个键值映射和一种遍历键的方法。之间最重要的区别 这些类是时间保证和键的顺序。

                1. HashMap 提供 0(1) 查找和插入。但是,如果您遍历键,则 键本质上是任意的。它由一个链表数组实现。
                2. TreeMap 提供 O(log N) 查找和插入。键是有序的,所以如果你需要遍历 按键排序,就可以了。这意味着键必须实现 Comparable 接口。TreeMap 由红黑树实现。
                3. LinkedHashMap 提供 0(1) 查找和插入。键按其插入顺序排序。它是 由双重链接的存储桶实现。

                假设您将一个空的 TreeMap、HashMap 和 LinkedHashMap 传递给以下函数:

                void insertAndPrint(AbstractMap<Integer, String> map) {
                  int[] array= {1, -1, 0};
                  for (int x : array) {
                    map.put(x, Integer.toString(x));
                  }
                  for (int k: map.keySet()) {
                   System.out.print(k + ", ");
                  }
                }
                

                每个的输出将如下所示。

                对于 HashMap,在我自己的测试中,输出是 {0, 1, -1},但它可以是任何顺序。没有任何保证 订购。
                树形图,输出为,{ -1, 0, 1}
                LinkedList,输出为,{ 1, -1, 0}

                【讨论】:

                  【解决方案17】:

                  HashMap
                  可以包含一个空键。

                  HashMap 没有顺序。

                  树图

                  TreeMap 不能包含任何空键。

                  TreeMap 保持升序。

                  LinkedHashMap

                  LinkedHashMap 可用于维护插入顺序,在哪些键上插入 Map,也可用于维护访问顺序,在哪些键上被访问。

                  示例::

                  1) HashMap map = new HashMap();

                      map.put(null, "Kamran");
                      map.put(2, "Ali");
                      map.put(5, "From");
                      map.put(4, "Dir");`enter code here`
                      map.put(3, "Lower");
                      for (Map.Entry m : map.entrySet()) {
                          System.out.println(m.getKey() + "  " + m.getValue());
                      } 
                  

                  2) TreeMap map = new TreeMap();

                      map.put(1, "Kamran");
                      map.put(2, "Ali");
                      map.put(5, "From");
                      map.put(4, "Dir");
                      map.put(3, "Lower");
                      for (Map.Entry m : map.entrySet()) {
                          System.out.println(m.getKey() + "  " + m.getValue());
                      }
                  

                  3) LinkedHashMap map = new LinkedHashMap();

                      map.put(1, "Kamran");
                      map.put(2, "Ali");
                      map.put(5, "From");
                      map.put(4, "Dir");
                      map.put(3, "Lower");
                      for (Map.Entry m : map.entrySet()) {
                          System.out.println(m.getKey() + "  " + m.getValue());
                      }
                  

                  【讨论】:

                    猜你喜欢
                    • 2012-05-13
                    • 1970-01-01
                    • 2013-08-12
                    • 2013-07-28
                    • 2011-01-27
                    • 2019-06-12
                    • 1970-01-01
                    • 2019-02-16
                    • 2013-12-26
                    相关资源
                    最近更新 更多