热门标签 | HotTags
当前位置:  开发笔记 > 编程语言 > 正文

HashMapJava8实现

如何解决《HashMapJava8实现》经验,为你挑选了3个好方法。

根据以下链接文档:Java HashMap Implementation

我对HashMap(或者更确切地说是增强HashMap)的实现感到困惑.我的疑问是:

首先

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

为什么以及如何使用这些常量?我想要一些明确的例子. 他们如何通过这个获得性能提升?

其次

如果您HashMap在JDK中看到源代码,您将找到以下静态内部类:

static final class TreeNode extends java.util.LinkedHashMap.Entry {
    HashMap.TreeNode parent;
    HashMap.TreeNode left;
    HashMap.TreeNode right;
    HashMap.TreeNode prev;
    boolean red;

    TreeNode(int arg0, K arg1, V arg2, HashMap.Node arg3) {
        super(arg0, arg1, arg2, arg3);
    }

    final HashMap.TreeNode root() {
        HashMap.TreeNode arg0 = this;

        while (true) {
            HashMap.TreeNode arg1 = arg0.parent;
            if (arg0.parent == null) {
                return arg0;
            }

            arg0 = arg1;
        }
    }
    //...
}

怎么用?我只想要解释算法.



1> Michael..:

HashMap包含一定数量的桶.它用于hashCode确定将这些存储器放入哪个存储桶.为简单起见,将其假设为模数.

如果我们的哈希码是123456并且我们有4个桶,123456 % 4 = 0那么该项目就在第一个桶中,即桶1.

HashMap中

如果我们的哈希码函数是好的,它将提供均匀分布,因此所有桶将在某种程度上同等使用.在这种情况下,存储桶使用链接列表来存储值.

链接桶

但是你不能依赖人们来实现好的哈希函数.人们经常会写出糟糕的哈希函数,这会导致非均匀分布.

糟糕的hashmap

这种分布越不均匀,我们越是从O(1)运算开始,越接近O(n)运算.

Hashmap的实现试图通过在存储桶变得太大的情况下将一些存储桶组织到树而不是链接列表来缓解这种情况.这TREEIFY_THRESHOLD = 8是为了什么.如果一个桶包含八个以上的项目,它应该成为一棵树.

树桶

这棵树是红黑树.它首先按哈希码排序.如果散列码相同,它使用compareTo的方法,Comparable如果对象实现该接口,否则身份哈希码.

如果从映射中删除条目,则存储桶中的条目数可能会减少,从而不再需要此树结构.这就是UNTREEIFY_THRESHOLD = 6它的用途.如果存储桶中的元素数量低于6,我们也可以回到使用链接列表.

最后,还有MIN_TREEIFY_CAPACITY = 64.

当哈希映射的大小增加时,它会自动调整自身大小以获得更多存储桶.如果我们有一个小的哈希映射,我们获得非常完整的桶的可能性是相当高的,因为我们没有很多不同的桶来放入内容.拥有更大的哈希映射会更好,更多的桶不够饱满.如果我们的哈希映射非常小,这个常量基本上不会开始将桶变成树 - 它应该首先调整大小.


为了回答有关性能增益的问题,我们添加了这些优化以改善最坏情况.我只是在推测,但如果你的hashCode功能不是很好的话,你可能只会看到明显的性能提升,因为这些优化.


图像是我的(感谢MSPaint).不管怎样你都可以重复使用它们


+1,我想补充一点,这种树方法减轻的特定情况是[哈希碰撞DOS攻击](http://programmingisterrible.com/post/40620375793/hash-table-denial-of-service-attacks -revisited).`java.lang.String`有一个确定性的,非加密的`hashCode`,因此攻击者可以通过碰撞hashCode轻松创建不同的字符串.在此优化之前,这可能会将HashMap操作降级为O(n)-time,现在它只会将它们降级为O(log(n)).
非均匀分布并不总是散列函数不良的标志.一些数据类型,例如`String`,具有比`int`哈希码大得多的值空间,因此,冲突是不可避免的.现在它取决于实际值,比如实际的`String`s,你放入地图,无论你是否获得均匀分布.糟糕的分配可能是运气不好的结果.

2> Eugene..:

更简单(尽可能简单)+更多细节.

这些属性取决于许多内部事物,这些内容很难理解 - 在直接转移到它们之前.

TREEIFY_THRESHOLD - >当一个单个铲斗达到此(和总数超过MIN_TREEIFY_CAPACITY),它被转换成一个完全平衡的红色/黑色树节点.为什么?因为搜索速度快.以不同的方式考虑它:

这将需要最多32个步骤,以搜索与桶/箱中的条目,Integer.MAX_VALUE的条目.

下一个主题的一些介绍.为什么箱/桶的数量总是2的幂?至少有两个原因:比模运算更快,负数上的模数将为负.你不能把一个条目放入一个"负面"桶:

 int arrayIndex = hashCode % buckets; // will be negative

 buckets[arrayIndex] = Entry; // obviously will fail

相反,有一个很好的技巧而不是模数:

 (n - 1) & hash // n is the number of bins, hash - is the hash function of the key

这在语义上与模运算相同.它会保留较低的位.当你这样做时,这有一个有趣的结果:

Map map = new HashMap<>();

在上面的例子中,根据您的哈希码的最后4位来决定条目的去向.

这是桶的倍增发挥作用的地方.在某些条件下(需要花费大量时间来详细解释),水桶的尺寸增加了一倍.为什么?当铲斗的尺寸加倍时,还会有一个钻头进入游戏.

所以你有16个桶 - 最后4位的哈希码决定了一个条目的位置.您将桶加倍:32个桶 - 最后5个桶决定进入的位置.

因此,此过程称为重新散列.这可能会变慢.那就是(对于那些关心的人),因为HashMap被"开玩笑"为:快速,快速,快速,懒散.还有其他实现 - 搜索暂停hashmap ...

现在UNTREEIFY_THRESHOLD在重新散列后发挥作用.此时,某些条目可能会从此二进制位移到另一些(它们会在(n-1)&hash计算中再添加一位- 因此可能会移动到其他存储区)并且可能会达到此目的UNTREEIFY_THRESHOLD.在这一点上,保持垃圾箱不会得到回报red-black tree node,但作为一个LinkedList替代,就像

 entry.next.next....

MIN_TREEIFY_CAPACITY是将某个存储桶转换为树之前的最小存储桶数.



3> Eran..:

TreeNode是另一种存储属于单个bin的条目的方法HashMap.在较旧的实现中,bin的条目存储在链表中.在Java 8中,如果bin中的条目数传递了threshold(TREEIFY_THRESHOLD),则它们存储在树结构中而不是原始链表中.这是一个优化.

从实施:

/*
 * Implementation notes.
 *
 * This map usually acts as a binned (bucketed) hash table, but
 * when bins get too large, they are transformed into bins of
 * TreeNodes, each structured similarly to those in
 * java.util.TreeMap. Most methods try to use normal bins, but
 * relay to TreeNode methods when applicable (simply by checking
 * instanceof a node).  Bins of TreeNodes may be traversed and
 * used like any others, but additionally support faster lookup
 * when overpopulated. However, since the vast majority of bins in
 * normal use are not overpopulated, checking for existence of
 * tree bins may be delayed in the course of table methods.


推荐阅读
  • Shodan简单用法Shodan简介Shodan是互联网上最可怕的搜索引擎,与谷歌不同的是,Shodan不是在网上搜索网址,而是直接进入互联网的背后通道。Shodan可以说是一款“ ... [详细]
  • 查找给定字符串的所有不同回文子字符串原文:https://www ... [详细]
  • 本文分享了一个关于在C#中使用异步代码的问题,作者在控制台中运行时代码正常工作,但在Windows窗体中却无法正常工作。作者尝试搜索局域网上的主机,但在窗体中计数器没有减少。文章提供了相关的代码和解决思路。 ... [详细]
  • Spring特性实现接口多类的动态调用详解
    本文详细介绍了如何使用Spring特性实现接口多类的动态调用。通过对Spring IoC容器的基础类BeanFactory和ApplicationContext的介绍,以及getBeansOfType方法的应用,解决了在实际工作中遇到的接口及多个实现类的问题。同时,文章还提到了SPI使用的不便之处,并介绍了借助ApplicationContext实现需求的方法。阅读本文,你将了解到Spring特性的实现原理和实际应用方式。 ... [详细]
  • 自动轮播,反转播放的ViewPagerAdapter的使用方法和效果展示
    本文介绍了如何使用自动轮播、反转播放的ViewPagerAdapter,并展示了其效果。该ViewPagerAdapter支持无限循环、触摸暂停、切换缩放等功能。同时提供了使用GIF.gif的示例和github地址。通过LoopFragmentPagerAdapter类的getActualCount、getActualItem和getActualPagerTitle方法可以实现自定义的循环效果和标题展示。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • 本文介绍了南邮ctf-web的writeup,包括签到题和md5 collision。在CTF比赛和渗透测试中,可以通过查看源代码、代码注释、页面隐藏元素、超链接和HTTP响应头部来寻找flag或提示信息。利用PHP弱类型,可以发现md5('QNKCDZO')='0e830400451993494058024219903391'和md5('240610708')='0e462097431906509019562988736854'。 ... [详细]
  • 解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法
    本文介绍了解决nginx启动报错epoll_wait() reported that client prematurely closed connection的方法,包括检查location配置是否正确、pass_proxy是否需要加“/”等。同时,还介绍了修改nginx的error.log日志级别为debug,以便查看详细日志信息。 ... [详细]
  • PDO MySQL
    PDOMySQL如果文章有成千上万篇,该怎样保存?数据保存有多种方式,比如单机文件、单机数据库(SQLite)、网络数据库(MySQL、MariaDB)等等。根据项目来选择,做We ... [详细]
  • Java程序设计第4周学习总结及注释应用的开发笔记
    本文由编程笔记#小编为大家整理,主要介绍了201521123087《Java程序设计》第4周学习总结相关的知识,包括注释的应用和使用类的注释与方法的注释进行注释的方法,并在Eclipse中查看。摘要内容大约为150字,提供了一定的参考价值。 ... [详细]
  • GreenDAO快速入门
    前言之前在自己做项目的时候,用到了GreenDAO数据库,其实对于数据库辅助工具库从OrmLite,到litePal再到GreenDAO,总是在不停的切换,但是没有真正去了解他们的 ... [详细]
  • macOS Big Sur全新设计大版本更新,10+个值得关注的新功能
    本文介绍了Apple发布的新一代操作系统macOS Big Sur,该系统采用全新的界面设计,包括图标、应用界面、程序坞和菜单栏等方面的变化。新系统还增加了通知中心、桌面小组件、强化的Safari浏览器以及隐私保护等多项功能。文章指出,macOS Big Sur的设计与iPadOS越来越接近,结合了去年iPadOS对鼠标的完善等功能。 ... [详细]
  • HashMap的相关问题及其底层数据结构和操作流程
    本文介绍了关于HashMap的相关问题,包括其底层数据结构、JDK1.7和JDK1.8的差异、红黑树的使用、扩容和树化的条件、退化为链表的情况、索引的计算方法、hashcode和hash()方法的作用、数组容量的选择、Put方法的流程以及并发问题下的操作。文章还提到了扩容死链和数据错乱的问题,并探讨了key的设计要求。对于对Java面试中的HashMap问题感兴趣的读者,本文将为您提供一些有用的技术和经验。 ... [详细]
  • python中安装并使用redis相关的知识
    本文介绍了在python中安装并使用redis的相关知识,包括redis的数据缓存系统和支持的数据类型,以及在pycharm中安装redis模块和常用的字符串操作。 ... [详细]
  • 如何使用台式电脑设置无线网络
    本文介绍了如何使用台式电脑设置无线网络的步骤,包括连接网线、更改IP、设置无线网络参数、重启路由器等,最后通过搜索无线信号来确认设置是否成功。 ... [详细]
author-avatar
人对方啥地位
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有