深入理解HashMap和TreeMap的区别

深入理解HashMap和TreeMap的区别文章目录简介 HashMap 和 TreeMap 本质区别排序区别 Null 值的区别性能区别共同点深入理解 HashMap 和 TreeMap 的区别简介 HashMap 和 TreeMap 是 Map 家族中非常常用的两个类 两个类在使用上和本质上有什么区别呢 本文将从这两个方面进行深入的探讨 希望能揭露其本质 HashMap 和 TreeMap 本质区别先看 HashMap 的定义 publicclassH

深入理解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

更多精彩内容且看:

  • 区块链从入门到放弃系列教程-涵盖密码学,超级账本,以太坊,Libra,比特币等持续更新
  • Spring Boot 2.X系列教程:七天从无到有掌握Spring Boot-持续更新
  • Spring 5.X系列教程:满足你对Spring5的一切想象-持续更新
  • java程序员从小工到专家成神之路(2020版)-持续更新中,附详细文章教程


版权声明:本文内容由互联网用户自发贡献,该文观点仅代表作者本人。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如发现本站有涉嫌侵权/违法违规的内容, 请联系我们举报,一经查实,本站将立刻删除。

发布者:全栈程序员-站长,转载请注明出处:https://javaforall.net/206529.html原文链接:https://javaforall.net

(0)
上一篇 2026年3月19日 下午3:29
下一篇 2026年3月19日 下午3:30


相关推荐

  • JVM调优工具详解

    JVM调优工具详解学习了JVM的一些调优工具为大家分享一下,现在把学习笔记总结记录一下,如果记录有些错误,还望指出。文章目录前言jdk自带工具一、Jmap1.1jps1.2jmap-histo1.3jmap-heap1.4jmap-dump二、Jstack三、Jinfo四、Jstat垃圾回收统计JVM运行情况预估年轻代对象增长的速率YoungGC的触发频率和每次耗时每次YoungGC后有多少对象存活和进入老年代FullGC的触发频率和每次耗时内存泄露到底是怎么回事五、ArthasArthas使用git

    2022年5月31日
    37
  • Elasticsearch-JSON串查询总结

    Elasticsearch-JSON串查询总结对Elasticsearch的JSON方式查询总结

    2022年5月6日
    379
  • Java四舍五入保留小数点后几位

    Java四舍五入保留小数点后几位(double)+Math.round返回double类型//案例:四舍五入保留小数点后1位doubled1=123.456;doubled2=654.321;doublev1=(double)Math.round(d1*10)/10;doublev2=(double)Math.round(d2*10)/10;System.out…

    2022年5月21日
    51
  • EasyDSS流媒体服务器软件-正式环境安装部署攻略

    EasyDSS流媒体服务器软件-正式环境安装部署攻略EasyDSS流媒体服务器软件,提供一站式的转码、点播、直播、时移回放服务,极大地简化了开发和集成的工作。其中,点播功能主要包含:上传、转码、分发。直播功能主要包含:直播、录像,直播支持RTMP输入,RTMP/HLS/HTTP-FLV的分发输出;录像支持自定义保存时长、检索及下载。提供丰富的二次开发接口,基于JSON的封装及HTTP调用。提供播放鉴权、推流鉴权等安全保证。提供用户及相关权限管理…

    2022年6月9日
    34
  • linux 系统查看网卡配置信息_如何查看自己电脑网卡配置

    linux 系统查看网卡配置信息_如何查看自己电脑网卡配置  Linux系统查看网卡配置,有几种方式,分述如下。方法一:ifconfig命令查看设置网卡ifconfig:查看所有活动网卡信息,能查看IP地址和子网掩码,但是不能查看网关和DNS地址),还可以临时设置某一网卡的IP地址和子网掩码。[root@cloudgw~]#ifconfigeth0:flags=4163<UP,BROADCAST,RUNNING,MULTICAST>mtu1500inet172.19.243.202ne

    2022年10月19日
    4
  • response.sendRedirect()与request.getRequestDispatcher().forward()区别

    response.sendRedirect()与request.getRequestDispatcher().forward()区别Servlet中response.sendRedirect()与request.getRequestDispatcher().forward(request,response)这两个对象都可以使页面跳

    2022年7月2日
    31

发表回复

您的邮箱地址不会被公开。 必填项已用 * 标注

关注全栈程序员社区公众号