Hashtable、HashMap、TreeMap

Hashtable、HashMap、TreeMap之间有什么异同?

  1. 都是以键值对的形式存储和操作数据的容器类型。
  2. HashTable 由早期Java类库提供的一个哈希表实现,是线程安全的,不支持 null 键和值 。出于同步导致的性能开销,已经很少被推荐使用。
  3. HashMap 由应用更加广泛的哈希表实现,基本上与 HsahTable 相同,但不是线程安全的,且支持 null 键和值。通常进行 put 或 get 操作时,其时间复杂度为 O(1) ,所以其是绝大部分利用键值对存取场景的首选。
  4. TreeMap是基于红黑树的一种提供顺序访问的Map,其时间复杂度一般是 O(log(n))的。具体顺序可有指定的 Comparator 来决定,或根据键的自然顺序来判断。TreeMap中当未实现 Comparator 接口时,key 不可以为null;当实现 Comparator 接口时,若未对null情况进行判断,则key不可以为null,反之亦然。

关于初始化容量与扩容机制

初始化时:

  • HashTable在不指定容量的情况下默认容量为 11 ,且不要求底层数组的容量一定要为 2 的整数次幂;
  • HashMap 默认容量为 16 ,且要求容量一定为 2 的整数次幂。

扩容时:

  • HashTable 将容量变为原来的2倍加1;
  • HashMap将容量变为原来的两倍。

有关线程安全性

  • HashTable 其方法函数都由 synchronized 修饰
  • HashMap 需要支持同步时:
    1)使用 Collections 的 synchronizedMap 方法;
    2)使用 基于 lock 实现锁分段的 ConCurrentHashMap 类(存放的数据分成一段一段的存储方式,然后给每一段数据分配一把锁,当一个线程占用锁访问其中一个段的数据时,其他段的数据也能被其他线程访问。ConcurrentHashMap不仅保证了多线程运行环境下的数据访问安全性,而且性能上有长足的提升。)

HashMap 出现哈希碰撞时是怎么处理的?

HashMap使用链表来解决碰撞问题,当发生碰撞了,对象将会储存在链表的下一个节点中。 HashMap在每个链表节点中储存键值对对象。当两个不同的键对象的hashcode相同时,它们会储存在同一个bucket位置的链表中,可通过键对象的equals()方法用来找到键值对。如果链表大小超过阈值(TREEIFY_THRESHOLD, 8),链表就会被改造为树形结构。

常见的哈希冲突解决方法?

开放地址法:
当关键字key的哈希地址p=H(key)出现冲突时,以p为基础,产生另一个哈希地址p1,如果p1仍然冲突,再以p为基础,产生另一个哈希地址p2,…,直到找出一个不冲突的哈希地址pi ,将相应元素存入其中。
再哈希法:
这种方法是同时构造多个不同的哈希函数:
Hi=RH1(key) i=1,2,…,k
当哈希地址Hi=RH1(key)发生冲突时,再计算Hi=RH2(key)……,直到冲突不再产生。这种方法不易产生聚集,但增加了计算时间。
链地址法:
将所有哈希地址为i的元素构成一个称为同义词链的单链表,并将单链表的头指针存在哈希表的第i个单元中,因而查找、插入和删除主要在同义词链中进行。链地址法适用于经常进行插入和删除的情况。
建立公共溢出区:
将哈希表分为基本表和溢出表两部分,凡是和基本表发生冲突的元素,一律填入溢出表。

posted on 2022-06-17 23:42  情陌人灬已不在  阅读(73)  评论(0编辑  收藏  举报

导航