热门标签 | 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.


推荐阅读
  • 缓存这个东西就是为了提高运行速度的,由于缓存是在寸土寸金的内存里面,不是在硬盘里面,所以容量是很有限的。LRU这个算法就是把最近一次使用时间离现在时间最远的数据删除掉。先说说List:每 ... [详细]
  • HashTable与ConcurrentHashMap均可实现HashMap的功能,对外提供了键值对存储的数据结构。但是在内部结构及实现上有何区别,性能上的差异到底在哪里又是如何导致的 ... [详细]
  • Iamtryingtomakeaclassthatwillreadatextfileofnamesintoanarray,thenreturnthatarra ... [详细]
  • Java容器中的compareto方法排序原理解析
    本文从源码解析Java容器中的compareto方法的排序原理,讲解了在使用数组存储数据时的限制以及存储效率的问题。同时提到了Redis的五大数据结构和list、set等知识点,回忆了作者大学时代的Java学习经历。文章以作者做的思维导图作为目录,展示了整个讲解过程。 ... [详细]
  • JavaSE笔试题-接口、抽象类、多态等问题解答
    本文解答了JavaSE笔试题中关于接口、抽象类、多态等问题。包括Math类的取整数方法、接口是否可继承、抽象类是否可实现接口、抽象类是否可继承具体类、抽象类中是否可以有静态main方法等问题。同时介绍了面向对象的特征,以及Java中实现多态的机制。 ... [详细]
  • 个人学习使用:谨慎参考1Client类importcom.thoughtworks.gauge.Step;importcom.thoughtworks.gauge.T ... [详细]
  • Java中包装类的设计原因以及操作方法
    本文主要介绍了Java中设计包装类的原因以及操作方法。在Java中,除了对象类型,还有八大基本类型,为了将基本类型转换成对象,Java引入了包装类。文章通过介绍包装类的定义和实现,解答了为什么需要包装类的问题,并提供了简单易用的操作方法。通过本文的学习,读者可以更好地理解和应用Java中的包装类。 ... [详细]
  • 先看官方文档TheJavaTutorialshavebeenwrittenforJDK8.Examplesandpracticesdescribedinthispagedontta ... [详细]
  • Week04面向对象设计与继承学习总结及作业要求
    本文总结了Week04面向对象设计与继承的重要知识点,包括对象、类、封装性、静态属性、静态方法、重载、继承和多态等。同时,还介绍了私有构造函数在类外部无法被调用、static不能访问非静态属性以及该类实例可以共享类里的static属性等内容。此外,还提到了作业要求,包括讲述一个在网上商城购物或在班级博客进行学习的故事,并使用Markdown的加粗标记和语句块标记标注关键名词和动词。最后,还提到了参考资料中关于UML类图如何绘制的范例。 ... [详细]
  • 重入锁(ReentrantLock)学习及实现原理
    本文介绍了重入锁(ReentrantLock)的学习及实现原理。在学习synchronized的基础上,重入锁提供了更多的灵活性和功能。文章详细介绍了重入锁的特性、使用方法和实现原理,并提供了类图和测试代码供读者参考。重入锁支持重入和公平与非公平两种实现方式,通过对比和分析,读者可以更好地理解和应用重入锁。 ... [详细]
  • HashMap:键值对(key-value):通过对象来对对象进行索引,用来索引的对象叫做key,其对应的对象叫做value.默认是1:1关系:存在则覆盖,当key已经存在,则利用新的va ... [详细]
  • 我有3个来自RESEARCHS的映射值,指定要使用参考数据集填充的行中的范围。该研究 ... [详细]
  • 转载自:http:www.blogjava.netCarpenterLeearchive20160427430268.html总体介绍之所以把HashSet和HashMa ... [详细]
  • Android系统源码分析Zygote和SystemServer启动过程详解
    本文详细解析了Android系统源码中Zygote和SystemServer的启动过程。首先介绍了系统framework层启动的内容,帮助理解四大组件的启动和管理过程。接着介绍了AMS、PMS等系统服务的作用和调用方式。然后详细分析了Zygote的启动过程,解释了Zygote在Android启动过程中的决定作用。最后通过时序图展示了整个过程。 ... [详细]
  • Java集合详解5:深入理解LinkedHashMap和LRU缓存
    Java集合详解5:深入理解LinkedHashMap和LRU缓存今天我们来深入探索一下LinkedHashMap的底层原理,并且使用linkedhashmap来实现LRU缓存。具体代码在我的 ... [详细]
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社区 版权所有