在面试的时候,面试官问到了平时常用的容器HashMap。问到的问题是,请你说说HashMap和HashTable的区别。

感觉自己回答得很笼统,比较混乱,现在总结一下:

 

1、是否线程安全

  • HashMap不是线程安全的,HashTable是线程安全的;【HashTable内部的方法基本都使用了synchronized关键字修饰】
  • 注意:现在HashTable在我们的开发中很少很少使用。如果你要保证线程安全,推荐使用ConcurrentHashMap

2、效率

  • 因为线程安全的问题,HashMap要比HashTable的效率高一点。

3、对于Null Key和Null Value的支持

  • HashMap中,null可以作为key,但是这样的key只能有一个;可以有一个或者多个键对应的value为null;
  • HashTable中不支持key为null,如果put使用null,那么就会抛出NullPointerException异常;

4、初始容量和每次扩充容量的大小不同

  • HashMap创建的时候如果不指定容量大小,初始容量大小为16,之后每次扩充,容量变为原来的2倍;
  • HashTable创建的时候如果不指定容量大小,初始容量大小为11,之后每次扩充,容量会变为2n + 1;
  • HashMap创建的时候给定初始容量大小,HashMap 会将其扩充为2的幂次方大小(HashMap 中的tableSizeFor()方法保证,下面给出了源代码)。也就是说 HashMap 总是使用2的幂作为哈希表的大小,后面会介绍到为什么是2的幂次方。
  • 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);
        }
  • 下面这个方法保证了 HashMap 总是使用2的幂作为哈希表的大小。
  •     /**
         * Returns a power of two size for the given target capacity.
         */
        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;
        }
  • HashTable创建时如果给定了容量初始值,那么 Hashtable 会直接使用你给定的大小

5、底层数据结构

  •  JDK1.8 以后的 HashMap 在解决哈希冲突时有了较大的变化,当链表长度大于阈值(默认为8)时,将链表转化为红黑树,以减少搜索时间;
  • Hashtable 没有这样的机制。
Logo

权威|前沿|技术|干货|国内首个API全生命周期开发者社区

更多推荐