深入理解HashMap和TreeMap的区别

简介

HashMap和TreeMap是Map家族中非常常用的两个类,两个类在使用上和本质上有什么区别呢?本文将从这两个方面进行深入的探讨,希望能揭露其本质。

HashMap和TreeMap本质区别

先看HashMap的定义:

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

再看TreeMap的定义:

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

从类的定义来看,HashMap和TreeMap都继承自AbstractMap,不同的是HashMap实现的是Map接口,而TreeMap实现的是NavigableMap接口。NavigableMap是SortedMap的一种,实现了对Map中key的排序。

这样两者的第一个区别就出来了,TreeMap是排序的而HashMap不是。

再看看HashMap和TreeMap的构造函数的区别。

public HashMap(int initialCapacity, float loadFactor)

HashMap除了默认的无参构造函数之外,还可以接受两个参数initialCapacity和loadFactor。

HashMap的底层结构是Node的数组:

transient Node<K,V>[] table

initialCapacity就是这个table的初始容量。如果大家不传initialCapacity,HashMap提供了一个默认的值:

static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // aka 16

当HashMap中存储的数据过多的时候,table数组就会被装满,这时候就需要扩容,HashMap的扩容是以2的倍数来进行的。而loadFactor就指定了什么时候需要进行扩容操作。默认的loadFactor是0.75。

static final float DEFAULT_LOAD_FACTOR = 0.75f;

再来看几个非常有趣的变量:

static final int TREEIFY_THRESHOLD = 8;
static final int UNTREEIFY_THRESHOLD = 6;
static final int MIN_TREEIFY_CAPACITY = 64;

上面的三个变量有什么用呢?在java 8之前,HashMap解决hashcode冲突的方法是采用链表的形式,为了提升效率,java 8将其转成了TreeNode。什么时候会发送这个转换呢?

这时候就要看这两个变量TREEIFY_THRESHOLD和UNTREEIFY_THRESHOLD。

有的同学可能发现了,TREEIFY_THRESHOLD为什么比UNTREEIFY_THRESHOLD大2呢?其实这个问题我也不知道,但是你看源代码的话,用到UNTREEIFY_THRESHOLD时候,都用的是<=,而用到TREEIFY_THRESHOLD的时候,都用的是>= TREEIFY_THRESHOLD - 1,所以这两个变量在本质上是一样的。

MIN_TREEIFY_CAPACITY表示的是如果table转换TreeNode的最小容量,只有capacity >= MIN_TREEIFY_CAPACITY的时候才允许TreeNode的转换。

TreeMap和HashMap不同的是,TreeMap的底层是一个Entry:

private transient Entry<K,V> root

他的实现是一个红黑树,方便用来遍历和搜索。

TreeMap的构造函数可以传入一个Comparator,实现自定义的比较方法。

public TreeMap(Comparator<? super K> comparator) {
this.comparator = comparator;
}

如果不提供自定义的比较方法,则使用的是key的natural order。

排序区别

我们讲完两者的本质之后,现在举例说明,先看下两者对排序的区别:

    @Test
public void withOrder(){
Map<String, String> books = new HashMap<>();
books.put("bob", "books");
books.put("c", "concurrent");
books.put("a", "a lock");
log.info("{}",books);
}
    @Test
public void withOrder(){
Map<String, String> books = new TreeMap<>();
books.put("bob", "books");
books.put("c", "concurrent");
books.put("a", "a lock");
log.info("{}",books);
}

同样的代码,一个使用了HashMap,一个使用了TreeMap,我们会发现TreeMap输出的结果是排好序的,而HashMap的输出结果是不定的。

Null值的区别

HashMap可以允许一个null key和多个null value。而TreeMap不允许null key,但是可以允许多个null value。

    @Test
public void withNull() {
Map<String, String> hashmap = new HashMap<>();
hashmap.put(null, null);
log.info("{}",hashmap);
}
    @Test
public void withNull() {
Map<String, String> hashmap = new TreeMap<>();
hashmap.put(null, null);
log.info("{}",hashmap);
}

HashMap会报出: NullPointerException。

性能区别

HashMap的底层是Array,所以HashMap在添加,查找,删除等方法上面速度会非常快。而TreeMap的底层是一个Tree结构,所以速度会比较慢。

另外HashMap因为要保存一个Array,所以会造成空间的浪费,而TreeMap只保存要保持的节点,所以占用的空间比较小。

HashMap如果出现hash冲突的话,效率会变差,不过在java 8进行TreeNode转换之后,效率有很大的提升。

TreeMap在添加和删除节点的时候会进行重排序,会对性能有所影响。

共同点

两者都不允许duplicate key,两者都不是线程安全的。

本文的例子https://github.com/ddean2009/learn-java-collections

欢迎关注我的公众号:程序那些事,更多精彩等着您!

更多内容请访问 www.flydean.com

深入理解HashMap和TreeMap的区别的更多相关文章

  1. Java中HashMap,LinkedHashMap,TreeMap的区别[转]

    原文:http://blog.csdn.net/xiyuan1999/article/details/6198394 java为数据结构中的映射定义了一个接口java.util.Map;它有四个实现类 ...

  2. HashMap与TreeMap的区别?

    HashMap与TreeMap的区别? 解答:HashMap通过hashcode对其内容进行快速查找,而TreeMap中所有的元素都保持着某种固定的顺序,如果你需要得到一个有序的结果你就应该使用Tre ...

  3. java面试题之HashMap和TreeMap的区别

    HashMap和TreeMap的区别 相同点: 都是以key和value的形式存储: key不可以重复: 都是线程不安全的: 不同点: HashMap的key可以为空 TreeMap的key值是有序的 ...

  4. HashMap,LinkedHashMap,TreeMap的区别(转)

    Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复.Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很快 ...

  5. Java中HashMap和TreeMap的区别深入理解

    首先介绍一下什么是Map.在数组中我们是通过数组下标来对其内容索引的,而在Map中我们通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value.这就是我们平时说的键值对. Has ...

  6. LinkedHashMap和hashMap和TreeMap的区别

    推荐博客:https://www.jianshu.com/p/8f4f58b4b8ab 区别: LinkedHashMap是继承于HashMap,是基于HashMap和双向链表来实现的. HashMa ...

  7. HashMap,LinkedHashMap,TreeMap的区别

    Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复. Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很 ...

  8. HashMap和TreeMap的区别

    HashMap:数组方式存储key/value,线程非安全,允许null作为key和value,key不可以 重复,value允许重复,不保证元素迭代顺序是按照插入时的顺序,key的hash值是先计算 ...

  9. HashMap与TreeMap的区别

    首先描述下什么是Map. 在数组中我们是通过数组的下标来对其内容进行索引的,而在Map中我们是通过对象对对象进行索引的,用来索引的对象叫做key,其对应的对象叫做value.这就是我们平常说的键值对. ...

  10. [转]HashMap,LinkedHashMap,TreeMap的区别

    Map主要用于存储健值对,根据键得到值,因此不允许键重复(重复了覆盖了),但允许值重复. Hashmap 是一个最常用的Map,它根据键的HashCode 值存储数据,根据键可以直接获取它的值,具有很 ...

随机推荐

  1. UserWarning: To get the last learning rate computed by the scheduler, please use `get_last_lr()`

    将 lr = scheduler.get_lr() 改为 lr = scheduler.get_last_lr()

  2. ASP.NET Core 选项

    目录 1,选项接口 2,注入配置与IOptions 3,IOptionsSnapshot 首先要了解 ASP.NET Core 中的配置,请点击这里了解:https://www.cnblogs.com ...

  3. 按值传递,引用传递 浅析java String ,对象与对象引用的区别

    目录 一.前言 二.何谓对象? 三.何谓对象引用? 四.创建对象 Vehicle veh1 = new Vehicle(); 五.参数传值 六.Java Sting 最后!有错误的地方欢迎指正 一.前 ...

  4. Codeforces Round 916 (Div. 3)(A~E2)

    A 统计一下每个字母的出现次数然后输出即可 #include <bits/stdc++.h> #define rep(i,a,b) for(register int i = (a); i ...

  5. XAF EFCore 示例

    前言 在DEV官方建议创建新的XAF项目推荐选择EFCore时,我也第一时间创建了XAF的EFCore项目,这也是我第一次创建这个类型的项目,之前一直使用XPO,避免不了要对比一下.如果熟悉XPO但不 ...

  6. 基于RocketMQ实现分布式事务

    背景 在一个微服务架构的项目中,一个业务操作可能涉及到多个服务,这些服务往往是独立部署,构成一个个独立的系统.这种分布式的系统架构往往面临着分布式事务的问题.为了保证系统数据的一致性,我们需要确保这些 ...

  7. hesitation 单词学习 犹豫 hes 就是 her 粘 助记单词 here

    hesitation 单词学习 犹豫 hes 就是 her 粘 助记单词 here hes + itation(ite + ate + ion) hesitation 美: [ˌhezɪˈteɪʃ(ə ...

  8. STM32 SPI DMA 源码解析及总结

    一 前言 最近在调试stm32的SPI时候i,遇到了一个非常诡异的问题.中间花费了不少时间才把问题搞定.这中间暴露的问题值得反思.借此机会,还是梳理一下stm32的SPI的代码做一个总结吧. 二 初始 ...

  9. const用法及与constexpr区别总结

    1.用const修饰函数的参数 参数是值传递 由于函数将自动产生临时变量复制该参数,该参数无需保护,没必要用const 参数是指针传递或者引用传递 const修饰的指针或引用所指向的值不可变.如果该参 ...

  10. Install fail! SyntaxError: Unexpected token 'h', "hub.com>","... is not valid JSON (file: C:\Users\Admin\Documents\uirecorder_test\node_modules\_mocha@5.2.0@mocha\package.json)

    uirecorder初始化时解析错误: PS C:\Users\Admin\Documents\uirecorder_test> PS C:\Users\Admin\Documents\uire ...