IdentityHashMap

IdentityHashMap

  • 前言
  • 属性
  • hash
  • 构造函数

前言

传统map中要求key的判断是equals,当我们想用对象作为key,并且需要地址相同时才能认为是相等的,这样传统map做不了,我们就要打破这一规定,比较key值用==

  • 为一组易变的对象维护代理对象
  • 基于一个对象的引用建立一个快速缓存
  • 保持一个有引用的对象的内存图

属性

/*
*
* 负载因子2/3,超过21的时候就要扩容,这个21也许是性能最佳点,所以指定21,
* 推算出32
*/
private static final int DEFAULT_CAPACITY = 32;
/*
* 最小扩容4,负载因子是2/3,最小4的时候,超过2就会扩容
*/
private static final int MINIMUM_CAPACITY = 4;
/*
*最大容量,2^31-1,要2次幂,2^30,但是key,value都在table中,所以它
* 只能装下hashMap一半的元素2^29
*/
private static final int MAXIMUM_CAPACITY = 1 << 29;

hash

确保hash是偶数,这样与运算长度,就能确保key落在偶数索引。这样在table中,偶数是key,vlue在奇数上,避免出现下面的情况:
IdentityHashMap_第1张图片

private static int hash(Object x, int length) {
        int h = System.identityHashCode(x);
        // Multiply by -254 to use the hash LSB and to ensure index is even
        //相当于乘以-254,确保hash值是偶数,左移1位就可以保证
        return ((h << 1) - (h << 8)) & (length - 1);
    }

IdentityHashMap_第2张图片
(h << 1) - (h << 8)确保了最后一位是0,决定了hash值是偶数,这样key只会在偶数索引上(最后一位是0,和任何数&运算都是偶数),然后低8位除去最后一位前7位都得以保留,其他位混合,这样更有利于Hash均匀。

构造函数

public IdentityHashMap() {
//无参构造,默认32
        init(DEFAULT_CAPACITY);
    }
public IdentityHashMap(int expectedMaxSize) {
//指定大小,如果小于0,抛出非法参数错误
        if (expectedMaxSize < 0)
            throw new IllegalArgumentException("expectedMaxSize is negative: "
                                               + expectedMaxSize);
        init(capacity(expectedMaxSize));
    }
//key和value都存储在table,所以指定容量后,实际给table大小是2倍   
private void init(int initCapacity) {
        table = new Object[2 * initCapacity];
    }
//按给定扩容阈值,超过它就会引发扩容  
private static int capacity(int expectedMaxSize) {
        // assert expectedMaxSize >= 0;
        return
 /**扩容阈值大于最大容量的1/3,直接给最大容量2^29创建,否则如果指定容量小于最小容量的
 * 2/3,直接最小容量4。其他则table长度的值就应该是3/2倍的扩容阈值,那应该是1.5倍啊,
 * 怎么是三倍?Integer.highestOneBit返回的是左侧最大2的次幂,已经减半了i - (i >>> 
 * 1),不就是0.5了吗,所以这里直接3倍了
 */
            (expectedMaxSize > MAXIMUM_CAPACITY / 3) ? MAXIMUM_CAPACITY :
            (expectedMaxSize <= 2 * MINIMUM_CAPACITY / 3) ? MINIMUM_CAPACITY :
            Integer.highestOneBit(expectedMaxSize + (expectedMaxSize << 1));
    }      

返回给定值左侧最大的2的次幂
IdentityHashMap_第3张图片

//获取i最高位1代表的2次幂,最高位1代表的权值
 public static int highestOneBit(int i) {
        // HD, Figure 3-1
        i |= (i >>  1);//将第二高位置1
        i |= (i >>  2);//将第二高位之后的两位置1
        i |= (i >>  4);
        i |= (i >>  8);
        i |= (i >> 16);//所有位都置1了
        //此时的如果i+1就是i右侧最小的2次幂(HashMap)
        return i - (i >>> 1);//i左侧最大的2次幂
    }

你可能感兴趣的:(集合框架,java)