java·数据结构·hashMap

特点

  • 线程不安全
  • HashMap、和Hashtable、SynchronizedMap区别:
    • HashMap 线程不安全,可以有null的key值或value值。
    • hashtable 线程安全,不能有null的key值或value值。
    • ConcurrentHashMap 线程安全,不能有null的key值或value值。删除操作比较费时。
    • SynchronizedMap 线程安全,可以有null的key值或value值。
      • 可以通过Collections.synchronizedMap(new HashMap<String, Object>())方式创建
    • 性能:HashMap>ConcurrentHashMap>SynchronizedMap>Hashtable

构造方法

相关参数

  • initialCapacity:初始最大容量,默认1<<4(2^4),内部实际使用的变量是threshold(默认容量) ,实际最大容量并没有存放。
  • loadFactor:加载因子(默认容量=初始最大容量*加载因子),默认0.75
  • threshold:默认容量,内部变量,根据initialCapacity生成。执行构造方法时,将输入的initialCapacity转为不小于当前数的最小的2^k的值,作为threshold。在第一次构建table时(第一次put,执行resize()方法),table的大小设置为threshold,然后让threshold = thresholdloadFactor;后续每一次resize,都是table的大小 = table的大小 2;threshold = threshold * 2;
  • 默认关系:threshold = initialCapacity * loadFactor(达到最大容量时不满足该等式)

平衡与折衷

  • 加载因子:hash表中元素的填满程度,加载因子越大,空间利用率越高,冲突机会越高(查询成本越高)

代码解析

  • public HashMap(int initialCapacity, float loadFactor)
public HashMap(int initialCapacity, float loadFactor) {
        /**初始最大容量为非负整数*/
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        /**
        * static final int MAXIMUM_CAPACITY = 1 << 30;
        * 当 initialCapacity 大于最大容量(2^30,约10.74亿)时,强制设置为容量为最大容量。
        */
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        /**
        * 加载因子为大于0的浮点数
        * public static boolean isNaN(float v) {
        *   return (v != v);
        * }
        * Float.isNaN(loadFactor):NaN(not-a-number),例如. float v = 0.0f/0.0f;
        */
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        /**赋值容量因子*/
        this.loadFactor = loadFactor;
        /**
        * 转换输入的初始最大容量为2^k,赋值给threshold作为实际最大容量
        * 这样做的意义待分析
        */
        this.threshold = tableSizeFor(initialCapacity);
    }

/**
* 获取不小于当前数的最小的2^k的值.
* 例如:31->32,65->128
*/
static final int tableSizeFor(int cap) {
    int n = cap - 1;
    n |= n >>> 1;
    n |= n >>> 2;
    n |= n >>> 4;
    n |= n >>> 8;
    n |= n >>> 16;
    return (n < 0) ? 1 : (n >= MAXIMUM_CAPACITY) ? MAXIMUM_CAPACITY : n + 1;
}
  • public HashMap(int initialCapacity)
public HashMap(int initialCapacity) {
    this(initialCapacity, DEFAULT_LOAD_FACTOR);
}
  • public HashMap()
/**
* 在resize()方法中设置threshold的值
* newCap = DEFAULT_INITIAL_CAPACITY;
* newThr = (int)(DEFAULT_LOAD_FACTOR * DEFAULT_INITIAL_CAPACITY);
*/
public HashMap() {
    this.loadFactor = DEFAULT_LOAD_FACTOR; // all other fields defaulted
}
  • public HashMap(Map<? extends K, ? extends V> m)
    • 待梳理
    public HashMap(Map<? extends K, ? extends V> m) {
      this.loadFactor = DEFAULT_LOAD_FACTOR;
      putMapEntries(m, false);
    }

小结:

  • java位运算相关知识待归纳。 (位运算的目的是提高效率)
    • 1 << k(2^k)
  • double和float区别待归纳。
  • HashMap、treemap、treenodes关系
  • 为什么n初始化构造map时,转换输入的初始最大容量为2^k,赋值给threshold作为实际最大容量。

猜你喜欢

转载自www.cnblogs.com/kunlingou/p/11067857.html