终于来到比较复杂的HashMap,由于内部的变量、内部类,方法都比较多,没法像ArrayList那样直接平铺开来说,因此准备从几个具体的角度来切入。
HashMap的每个存储位置,又叫做一个桶,当一个Key&价值进入地图的时候,依据它的散列值分配一个桶来存储。
看一下桶的定义:表就是所谓的桶结构,说白了就是一个节点数组。
瞬态Node[]表; 瞬态int大小;
<强>节点
强>
HashMap是一个地图结构,它不同于收集结构,不是存储单个对象,而是存储键值对。
因此内部最基本的存储单元是节点:节点。
节点的定义如下:
类Node实现Map.Entry { 最后int散列; 最后K键; V值; Node 下一个; }
可见节点除了存储关键,影响无锡市,散列三个值之外,还有一个下一个指针,这样一样,多个节点可以形成一个单向列表。这是解决哈希冲突的一种方式,如果多个节点被分配到同一个桶,可以组成一个链表。
HashMap内部还有另一种节点类型,叫做TreeNode:
类TreeNode扩展LinkedHashMap.Entry { TreeNode 父母;//红黑树链接 TreeNode 离开; TreeNode 对的; TreeNode prev;//需要拆开下删除 布尔红; }
TreeNode是从节点继承的,它可以组成一棵红黑树。为什么还有这个东东呢?上面说过,如果节点的被哈希到同一个桶,那么可能导致链表特别长,这样一来访问效率就会急剧下降。此时如果关键是可比较的(实现了可比接口),HashMap就将这个链表转成一棵平衡二叉树,来挽回一些效率。在实际使用中,我们期望这种现象永远不要发生。
有了这个知识,就可以看看HashMap几个相关常量定义了:
静态最终int TREEIFY_THRESHOLD=8; 静态最终int UNTREEIFY_THRESHOLD=6; 静态最终int MIN_TREEIFY_CAPACITY=64;
-
<李> TREEIFY_THRESHOLD,当某个桶里面的节点数达到这个数量,链表可转换成树;李>
<李> UNTREEIFY_THRESHOLD,当某个桶里面数低于这数量,树转换回链表;李>
<李> MIN_TREEIFY_CAPACITY,如果桶数量低于这个数,那么优先扩充桶的数量,而不是将链表转换成树;李>
<强>把方法:Key&价值强>
插入接口:
公共V把(K键,V值){ 返回putVal(散列(关键)、关键值,假的,真的); } 最后一个int散列(对象键){ int h; 返回(关键==null) & # 63;0:(h=key.hashCode ()) ^ (h祝辞祝辞祝辞16); }
把方法调用了私有方法putVal,不过值得注意的是,关键的哈希值不是直接用的hashCode,最终的散列=(hashCode右移16)^ hashCode。
在将散列值映射为桶位置的时候,取的是散列值的低位部分,这样如果有一批关键的仅高位部分不一致,就会聚集的同一个桶里面。(如果桶数量比较少,关键是浮动类型,且是连续的整数,就会出现这种情况)。
执行插入的过程:
V putVal (int散列,K键,V值,布尔> 公共V删除(对象键){ Nodee; 返回(e=removeNode(散列(关键),钥匙,null,假的,真的))==null & # 63; 空:e.value; } Node removeNode (int散列、对象关键对象的值, 布尔matchValue,布尔活动){ Node []选项卡;Node p;整数n,指数;//代码段1 如果((标签=表)!=零,,(n=tab.length)比;0,, (p=选项卡(指数=(n - 1),哈希)!=null) {//代码段2: Node e节点=零;K K;V V; 如果(p。散列==散列,, ((k=p.key)==关键| |(关键!=零,,key.equals (k)))) 节点=p;//代码段3: else if ((e=p.next) !=null) {//代码段3.1: 如果(p instanceof TreeNode) 节点=((TreeNode ) p)。getTreeNode(散列键); 其他{//代码段3.2: {做 如果(e。散列==散列,, ((k=e.key)==关键| | (钥匙!=零,,key.equals (k)))) { 节点=e; 打破; } p=e; },((e=e.next) !=null); } }//代码段4: 如果(节点!=零,,(!matchValue | | (v=node.value)价值==| | (价值!=零,,value.equals (v)))) {//代码段4.1: 如果节点instanceof TreeNode) ((TreeNode )节点)。removeTreeNode(选项卡,这活动);//代码段4.2: else if(节点==p) 选项卡(指数)=node.next;//代码段4.3: 其他的 p。下一个=node.next; + + modCount; ——大小; afterNodeRemoval(节点); 返回节点; } } 返回null; } java基础类型源码解析之多角度讲HashMap