• java.util.HashMap源码初探


    对于一个存储类的分析,无非从两点入手:存储用的数据结构,存储的运行机制。

    数据结构:

    数组

        /**
         * The table, resized as necessary. Length MUST Always be a power of two.
         */
        transient Entry[] table;


    Entry

    链表格式。

    也即,HashMap中采用的是“链接法”来处理碰撞问题的。


    运行机制:

    put、get

    put方法

        public V put(K key, V value) {
            if (key == null)
                return putForNullKey(value);
            int hash = hash(key.hashCode());
            int i = indexFor(hash, table.length);
            for (Entry<K,V> e = table[i]; e != null; e = e.next) {
                Object k;
                if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
                    V oldValue = e.value;
                    e.value = value;
                    e.recordAccess(this);
                    return oldValue;
                }
            }
    
            modCount++;
            addEntry(hash, key, value, i);
            return null;
        }


    get方法

        public V get(Object key) {
            if (key == null)
                return getForNullKey();
            int hash = hash(key.hashCode());
            for (Entry<K,V> e = table[indexFor(hash, table.length)];
                 e != null;
                 e = e.next) {
                Object k;
                if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
                    return e.value;
            }
            return null;
        }


    可以看出,重要的一句代码为:

    if (e.hash == hash && ((k = e.key) == key || key.equals(k)))


    这句代码的作用是判断两个Key对象是否“相同”,这里的相同的意思是指两个Key完全可以不分彼此,可以作为同一个Key使用。

    在put方法中,如果两个Key的hashCode相同,且equals符合,这里是把原有的的value替换成新的value。


    测试代码:

    package test.junit;
    
    import java.util.HashMap;
    
    import junit.framework.TestCase;
    
    /**
     * HashMap中判断两个Key是否相同:先判断hashCode,在判断是否equals
     * e.hash == hash && ((k = e.key) == key || key.equals(k))
     * @author xuefeng
     *
     */
    public class HashMapTest extends TestCase {
    	
    	/**
    	 * v1和v4的hashCode相同,但是equals不符合,所以v1和v4会组成一个链表。
    	 */
    	public void testKey1() {
    		HashMap<Key, Value> map = new HashMap<Key, Value>();
    		Key k1 = new Key(1);
    		Key k4 = new Key(4);
    		Value v1 = new Value(1);
    		Value v4 = new Value(4);
    		
    		map.put(k1, v1);
    		map.put(k4, v4);
    		
    		assertEquals(v1, map.get(k1));
    		assertEquals(v4, map.get(k4));
    	}
    	
    	/**
    	 * v1和v4的hashCode相同,而且equals也符合,所以v1会被v4替换掉,k1和k4指向同一个v4。
    	 */
    	public void testKey2() {
    		HashMap<Key2, Value> map = new HashMap<Key2, Value>();
    		Key2 k1 = new Key2(1);
    		Key2 k4 = new Key2(4);
    		Value v1 = new Value(1);
    		Value v4 = new Value(4);
    		
    		map.put(k1, v1);
    		map.put(k4, v4); // 这里会替换掉v1
    		
    //		assertEquals(v1, map.get(k1));
    		assertEquals(v4, map.get(k1));
    		assertEquals(v4, map.get(k4));
    	}
    }
    
    class Key {
    	public int m;
    	
    	public Key(int m) {
    		this.m = m;
    	}
    	
    	@Override
    	public int hashCode() {
    		return m%3;
    	}
    }
    
    class Value {
    	public int m;
    	
    	public Value(int m) {
    		this.m = m;
    	}
    }
    
    class Key2 {
    	public int m;
    	
    	public Key2(int m) {
    		this.m = m;
    	}
    	
    	@Override
    	public int hashCode() {
    		return m%3;
    	}
    	
    	@Override
    	public boolean equals(Object obj) {
    		if(obj == null || !(obj instanceof Key2)) return false;
    		
    		Key2 other = (Key2)obj;
    		
    		return this.hashCode() == other.hashCode();
    	}
    }
    


  • 相关阅读:
    mysql sleep
    mysql 与grafana数据展示时的时间处理
    DevSecOps调研
    django 启动mysql加载错误信息
    kubebuilder operator
    mysql 修改密码
    mysql 实例管理工具
    一文详解JackSon配置信息
    表达式计算(双栈实现)
    【转!】metersphere win源码部署
  • 原文地址:https://www.cnblogs.com/javawebsoa/p/2990637.html
Copyright © 2020-2023  润新知