treeify

为什么Map桶中个数超过8才转为红黑树

爱⌒轻易说出口 提交于 2020-02-28 17:50:31
要弄明白这个问题,我们首先要明白为什么要转换,这个问题比较简单,因为Map中桶的元素初始化是链表保存的,其查找性能是O(n),而树结构能将查找性能提升到O(log(n))。当链表长度很小的时候,即使遍历,速度也非常快,但是当链表长度不断变长,肯定会对查询性能有一定的影响,所以才需要转成树。至于为什么阈值是8,我想,去源码中找寻答案应该是最可靠的途径。 8这个阈值定义在HashMap中,如下所示,这段注释只说明了8是bin(bin就是bucket,即HashMap中hashCode值一样的元素保存的地方)从链表转成树的阈值,但是并没有说明为什么是8: /** * The bin count threshold for using a tree rather than list for a * bin. Bins are converted to trees when adding an element to a * bin with at least this many nodes. The value must be greater * than 2 and should be at least 8 to mesh with assumptions in * tree removal about conversion back to plain bins upon

JDK8 HashMap的实现原理

烂漫一生 提交于 2020-02-28 17:30:35
一、HashMap结构图 1、JDK7及之前 2、JKD8及之后 由上面结构图可知,在JDK7及之前,HashMap采用 位桶+链表 实现,即使用链表处理冲突,同一hash值的链表都存储在一个链表里。但是当位于一个桶中的元素较多,即hash值相等的元素较多时,通过key值依次查找的效率较低。而JDK8对HashMap做了优化,采用 位桶+链表+红黑树 实现,当链表长度超过阈值(8)时,将链表转换为红黑树,使得HashMap存取速度更快。 二、HashMap重要参数 不同JDK版本中HashMap重要参数对比 属性名 属性说明 JDK7 JDK8 loadFactor 加载因子,初始值=0.75,与扩容有关 √ √ threshold 临界值,与HashMap扩容相关 √ √ modCount map中数据改变次数的统计 √ √ DEFAULT_INITIAL_CAPACITY 默认的初始容量 ,=1<<4=16 √ √ MAXIMUM_CAPACITY 最大容量,=1<<30 √ √ DEFAULT_LOAD_FACTOR 默认加载因子,=0.75 √ √ TREEIFY_THRESHOLD 使用TreeNode的临界值,默认=8 × √ UNTREEIFY_THRESHOLD 与split方法有关 × √ MIN_TREEIFY_CAPACITY 最小TreeNode的容量为64

HashMap结构与图解

ε祈祈猫儿з 提交于 2020-02-26 01:23:56
主干结构 1.主干结构 Node<K,V>[] table Node<K,V> implement Map.Entry<K,V> //Node点 static class Node<K,V> implements Map.Entry<K,V> { final int hash; //用来定位数组索引位置 final K key; V value; Node<K,V> next; //链表的下一个node Node(int hash, K key, V value, Node<K,V> next) { ... } public final K getKey(){ ... } public final V getValue() { ... } public final String toString() { ... } public final int hashCode() { ... } public final V setValue(V newValue) { ... } public final boolean equals(Object o) { ... } } 2.HashMap哈希桶数组table的长度length大小必须为2的n次方(一定是合数),主要是为了在取模和扩容时做优化,同时减少冲突,HashMap定位哈希桶索引位置时,也加入了高位参与运算的过程。 3

面试高频问题:HashMap实现原理

你。 提交于 2019-12-10 16:02:00
今天给同学们讲讲一个面试经常遇到的高频问题,HashMap实现原理,希望在金三银四的季节对同学们有帮助。 HashMap结构图目录 一、唠叨 二、解析思路 三、get方法 四、put方法 五、resize方法 一、唠叨 认真阅读了下HashMap的实现方式,也参考了网上别人的一些解析,个人觉得还是有些东西想说。网上有的文章名字为HashMap源码解析,实际上就是给它里面的一些方法加上一些注释而已,有不少都是这样的。 我自己看源码的时候,发现不是别人不想解析,而是它的实现真的需要亲自研读,多理顺几遍才知道怎么回事。 我在这里解析的文字描述也较多,不管谁的解析,自己也都要看一下JDK源码的具体实现,我们仅提供参考而已。 二、解析思路 源码不太方便看,先说明一下我的阅读思路。 1.把常用的几个方法拷贝到文本编辑器里面。 2.HashMap中不同的时候会有不同的流程,梳理方法中的逻辑流程。就像采用极端法,采用特殊的数据,然后查看方法执行语句。未执行的语句暂时不考虑。 3.注释源码...我觉得HashMap的实现方式不够好,关键的几个方法里面包含的情况太多了,阅读起来是有难度的,而写程序的目的之一不就是让其他开发者阅读吗?一个方法内部做了太多的事情,违反了代码整洁的规则,一个函数做要尽量少的事情。 解析 之前稍微介绍了一些HashMap的特性,HashMap初探。 (https://www

equals & hashCode

做~自己de王妃 提交于 2019-12-07 15:53:43
equals() 与hasCode() 都定义在Object.java中。equals 默认使用“==”来比较对象。 public boolean equals(Object obj) { return (this == obj); } public native int hashCode(); 在对于hashCode()的javadoc中明确表明: hashCode是用在hash表中的。 equals相同,hashCode一定相同(但hashCode相同,equals不一定相同) ,这样有利于提高hash表的效率。 eg. 验证: hashCode相同,equals不一定相同 public static void main(String[] args) { Long a = 1L; Integer b = 1; System.out.println(b.hashCode() == a.hashCode()); // true System.out.println(b.equals(a)); // false } 执行结果: true、 false。 java.lang下各类的重写 对于String: public int hashCode() { int h = hash; if (h == 0 && value.length > 0) { char val[] = value;

集合之HashMap

China☆狼群 提交于 2019-12-04 11:51:49
首先看看HashMap在JDK中的继承层次: 在HashSet中,我们说过元素使用hashcode保存的存储结构: 保存的键值对根据键得到hashcode,然后和bucket总数取余得到位置索引,然后将数据保存到后面的链表中。 在HashMap中定义了一系列的属性,看看都有什么,先不管什么意思,使用到的时候再说: // 默认的容量初始化大小 static final int DEFAULT_INITIAL_CAPACITY = 1 << 4; // 最大的容量 static final int MAXIMUM_CAPACITY = 1 << 30; // 默认的加载因子 static final float DEFAULT_LOAD_FACTOR = 0.75f; // 限定值,如果超过这个值,将链表转为红黑树 static final int TREEIFY_THRESHOLD = 8; // 少于这个值,红黑树转为链表 static final int UNTREEIFY_THRESHOLD = 6; // 避免扩容和树形化的冲突,元素必须大于这个值,才扩容。这个值大于 4 * TREEIFY_THRESHOLD static final int MIN_TREEIFY_CAPACITY = 64; 构造器有三个: public HashMap() { this

Hash和HashCode深入理解

走远了吗. 提交于 2019-12-01 01:00:31
目录介绍 1.Hash的作用介绍 1.1 Hash的定义 1.2 Hash函数特性 1.3 Hash的使用场景 2.如何判断两个对象相等 2.1 判断两个字符串 2.2 判断两个int数值 2.3 其他基本类型 3.HashCode深入分析 3.0 HashCode是什么 3.1 为什么要重写HashCode 3.2 HashCode源代码分析 3.3 HashCode带来的疑问 3.4 HashCode的作用 3.5 HashMap中的HashCode 3.6 可直接用hashcode判断两个对象是否相等 4.Hash表是什么 4.1 Hash表定义 4.2 Hash表简单介绍 5.Hash中的算法应用 5.1 基础算法 5.2 经典算法[摘自网络] 5.3 Hash碰撞[摘自网络] 6.Hash在Java中的应用场景 6.1 equals与hashCode有两个注意点 6.2 以HashSet为例说明hashCode()的作用 6.3 以HashMap为例说明Hash的作用 6.4 7.版本更新情况 8.其他介绍 1.Hash的作用介绍 1.1 Hash的定义 散列(哈希)函数 把任意长度的输入(又叫做预映射pre-image)通过散列算法变换成固定长度的输出,该输出就是散列值,是一种压缩映射。 或者说一种将任意长度的消息压缩到某一固定长度的消息摘要的函数。 1.2

WeakHashMap,源码解读

泪湿孤枕 提交于 2019-11-29 07:51:03
概述 WeakHashMap 也是Map接口的一个实现类,它与HashMap相似,也是一个哈希表,存储key-value pair,而且也是非线程安全的。不过WeakHashMap并没有引入红黑树来尽量规避哈希冲突带来的影响,内部实现只是 数组+单链表 。此外,WeakHashMap与HashMap 最大的不同之处 在于,WeakHashMap的key是 “弱键”(weak keys) ,即 当一个key不再正常使用时,key对应的key-value pair将自动从WeakHashMap中删除,在这种情况下,即使key对应的key-value pair的存在,这个key依然会被GC回收,如此以来,它对应的key-value pair也就被从map中有效地删除了。 Java的四种引用 在正式进入WeakHashMap源码之前,我们需要先对 “弱引用” 有一个基本的认识,为此这里先介绍一下JDK 1.2开始推出的四种引用: 强引用(Strong Reference) 强引用是指在程序代码之中普遍存在的,类似 Objective obj = new Object() 这类的引用,只要强引用还存在,垃圾收集器永远不会回收掉被引用的对象。 软引用(Soft Reference) 软引用是用来描述一些还有用但并非必需的对象,对于软引用关联着的对象, 在系统将要发生内存溢出异常之前