0
点赞
收藏
分享

微信扫一扫

2.集合(Map)

  在我们的代码开发中,Map键值对集合是我们经常使用的数据存储结构,他用着O(1)的查询时间复杂度,为我们的查询操作提供了优质的效率。

1.Map

1.1 HashMap与HashTable的区别

  1. 线程是否安全HashMap 是非线程安全的Hashtable 是线程安全的,因为 Hashtable 内部的方法基本都经过synchronized 修饰。(如果要保证线程安全最好使用 ConcurrentHashMap )
  2. 效率:因为线程安全的问题HashMap 要比 Hashtable 效率高一点。另外,Hashtable 基本被淘汰,不要在代码中使用它
  3. 对NULL key和NULLvalue的支持HashMap 可以存储 null 的 key 和 value,但 null 作为键只能有一个null 作为值可以有多个Hashtable 不允许有 null 键和 null 值否则会抛出 NullPointerException
  4. 初始容量大小和每次扩容大小的不同:① 创建时如果不指定容量初始值,Hashtable 默认的初始大小为 11每次扩充容量变为原来的 2n+1HashMap 默认的初始化大小为 16每次扩充容量变为原来的 2 倍。② 创建时若给定容量初始值,那么 Hashtable 会直接使用你给定的大小,而 HashMap 会将其扩充为 2 的幂次方大小HashMap 中的tableSizeFor()方法保证,下面给出了源代码)。也就是说 HashMap 总是使用 2 的幂作为哈希表的大小,后面会介绍到为什么是 2 的幂次方。
  5. 底层数据结构: JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为 8)时,将链表转化为红黑树(将链表转换成红黑树前会判断,如果当前数组的长度小于 64,那么会选择先进行数组扩容,而不是转换为红黑树),以减少搜索时间(后文中我会结合源码对这一过程进行分析)。Hashtable 没有这样的机制。

HashMap中带有初始容量的构造函数

public HashMap(int initialCapacity, float loadFactor) {
        if (initialCapacity < 0)
            throw new IllegalArgumentException("Illegal initial capacity: " +
                                               initialCapacity);
        if (initialCapacity > MAXIMUM_CAPACITY)
            initialCapacity = MAXIMUM_CAPACITY;
        if (loadFactor <= 0 || Float.isNaN(loadFactor))
            throw new IllegalArgumentException("Illegal load factor: " +
                                               loadFactor);
        this.loadFactor = loadFactor;
        this.threshold = tableSizeFor(initialCapacity);
    }
     public HashMap(int initialCapacity) {
        this(initialCapacity, DEFAULT_LOAD_FACTOR);
    }

tableSizeFor()方法保证了HashMap总是使用2的幂作为其大小。

static 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 >= MAXIMUN_CAPACITY) ? MAXIMUN_CAPCITY : n+1;
}

  当我给定cap值为16时,最后输出位14。并没有值为2的次幂。这个后续再理解。



举报

相关推荐

0 条评论