Java SE HashMap的底层实现

Posted Steve Yu

tags:

篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了Java SE HashMap的底层实现相关的知识,希望对你有一定的参考价值。

1.hash散列算法

  由于hashmap在存储过程中是数组加链表的存储过程,所以定义数组长度为16(建议是2的n次幂的长度),之后进行每个数组的地址都指向一个链表进行存储

 

  hash表算法可对数组长度length取余,如果length是2的n次幂,则可对length-1取位运算&

  例如,任意长度8是2的3次幂,随机的int值对8取余,和对7进行&运算得到的结果是一样的

int a=33565366;
System.out.println(a%8);
System.out.println(a&7);

  在jdk 7之前的源码中,则对hash凑得进行了2次散列处理,为了使散列更均匀

  在jdk 8往后,数组长度大于8时,链表转换为红黑树,大大提高了查找速率

  

2.手工实现hashMap

  取数据

    1.首先通过key计算hashcode来得到数组的存储,再通过next便利链表进行查找比较,直到返回true的节点对象为止

    2.Java中有规定,两个内容相同的(调用equals方法值为true的)对象必须有想等的hashcode,如果两个对象内容相等,而hashcode的值不一样,则会产生悖论

  扩容问题

    1.jdk7之前

    hashMap的位桶数组,初始大小为16,实际使用时,大小可变,如果位桶数组中元素个数达到(0.75*数组length),就重新调整数组为2倍大小,扩容是个耗时的过程,相当于重新定义数组和链表,进行复制操作

    2.jdk8之后

    位桶数组初始大小为16,当链表长度大于8时,将链表中各个元素拷贝到红黑树上,大大提高了查找效率

3.源代码

  

package com.littlepage.HashMap;
/**
 * 用于LittlePagesHashMap的Node
 * @author LittlePage
 */
public class Node<K,V> {
    private int hash;
    private K key;
    private V value;
    private Node<K,V> next;
    
    public Node(K key, V value) {
        super();
        this.key = key;
        this.value = value;
    }

    public int getHash() {
        return hash;
    }

    public void setHash(int hash) {
        this.hash = hash;
    }

    public K getKey() {
        return key;
    }

    public void setKey(K key) {
        this.key = key;
    }

    public V getValue() {
        return value;
    }

    public void setValue(V value) {
        this.value = value;
    }

    public Node<K, V> getNext() {
        return next;
    }

    public void setNext(Node<K, V> next) {
        this.next = next;
    }

    @Override
    public String toString() {
        return "(" + key + "," + value + ")";
    }
    
    
    
    
}
package com.littlepage.HashMap;

public class LittlePagesHashMap<K,V> {
    
    
    Object[] table=new Node[16];       //位桶数组
    
    int size;//存放键值对个数
    
    
    public LittlePagesHashMap(){
        table=new Node[16];
    }
    
    public void put(K key,V value){
        //定义了新的节点对象
        Node<K,V> newNode=new Node<>(key,value);
        newNode.setHash(myHash(key.hashCode(), table.length));
        
        @SuppressWarnings("unchecked")
        Node<K,V> temp=(Node<K, V>) table[newNode.getHash()];
        if(temp==null){
            table[newNode.getHash()]=newNode;
        }else{
            while(temp.getNext()!=null){
                if(temp.getKey().equals(newNode.getKey())){
                    temp.setValue(newNode.getValue());
                    size++;
                    return;
                }
                temp=temp.getNext(); 
            }
            temp.setNext(newNode);
        }
        size++;
    }
    
    public int myHash(int hashcode,int length){
        return hashcode&(length-1);
    }
    
    @Override
    public String toString(){
        StringBuilder sb=new StringBuilder();
        sb.append("[");
        for(int i=0;i<table.length;i++){
            if(table[i]==null) continue;
            else{
                @SuppressWarnings("unchecked")
                Node<K,V> temp=(Node<K, V>) table[i];
                sb.append(temp);
                while((temp=temp.getNext())!=null){
                    sb.append(","+temp);
                }
                sb.append("]");
            }
        }
        return sb.toString();
    }
}
package com.littlepage.HashMap;

public class Test {
    public static void main(String[] args) {
        LittlePagesHashMap<String, String> a=new LittlePagesHashMap<>();
        a.put("a", "gg");
        a.put("12", "pp");
        System.out.println(a);
    }
}

 

以上是关于Java SE HashMap的底层实现的主要内容,如果未能解决你的问题,请参考以下文章

JAVA SE ArrayList 底层实现

JAVA进阶篇——HashMap底层实现解析

Java中HashMap底层实现原理(JDK1.8)源码分析

Java中HashMap底层实现原理(JDK1.8)源码分析

Java中HashMap底层实现原理(JDK1.8)源码分析

算法/结构HashMap 底层结构 二叉树 红黑树 自用整理