20220901学习内容 HashMap和Tree Map总结:

一    HashMap总结:

===概述:
HashMap是基于哈希表(散列表),实现Map接口的双列集合,数据结构是“链表散列”,
也就是数组+链表 ,key唯一的value可以重复,允许存储null 键null 值,元素无序。

===工作原理:
HashMap在Map.Entry静态内部类实现中存储key-value对。HashMap使用哈希算法,
在put和get方法中,它使用hashCode()和equals()方法。当我们通过传递key-value对调用put方法的时候,HashMap使用Key hashCode()和哈希算法来找出存储key-value对的索引。Entry存储在LinkedList中,所以如果存在entry,它使用equals()方法来检查传递的key是否已经存在,如果存在,它会覆盖value,如果不存在,它会创建一个新的entry然后保存。当我们通过传递key调用get方法时,它再次使用hashCode()来找到数组中的索引,然后使用equals()方法找出正确的Entry,然后返回它的值。

HashMap默认的初始容量是16,负载因子是0.75。【阀值= 为负载因子 X 容量】
无论何时我们尝试添加一个entry,如果map的大小比阀值大的时候,HashMap会对map的内容进行重新哈希,且使用更大的容量。容量总是2的幂,所以如果你知道你需要存储大量的key-value对,比如缓存从数据库里面拉取的数据,使用正确的容量和负荷系数对HashMap进行初始化是个不错的做法。

===hashCode()和equals()方法有何重要性:
HashMap使用Key对象的hashCode()和equals()方法去决定key-value对的索引。当我们试着从HashMap中获取值的时候,
这些方法也会被用到。如果这些方法没有被正确地实现,在这种情况下,两个不同Key也许会产生相同的hashCode()和equals()输出,
HashMap将会认为它们是相同的,然后覆盖它们,而非把它们存储到不同的地方。
同样的,所有不允许存储重复数据的集合类都使用hashCode()和equals()去查找重复,所以正确实现它们非常重要。
equals()和hashCode()的实现应该遵循以下规则:
(1)如果o1.equals(o2),那么o1.hashCode() == o2.hashCode()总是为true的。
(2)如果o1.hashCode() == o2.hashCode(),并不意味着o1.equals(o2)会为true。
为什么重写equals()的时候一定要重写hashcode():
HashMap中,如果要比较key是否相等,要同时使用这两个函数!因为自定义的类的hashcode()方法继承于Object类,
其hashcode码为默认的内存地 址,这样即便有相同含义的两个对象,比较也是不相等的,例如,生成了两个“羊”对象,
正常理解这两个对象应该是相等的,但如果你不重写hashcode()方法的话,则比较是不相等的。

 - 结构特点:
Java8-中的HashMap是基于“数组+链表”的方式(链表法解决冲突),
 到了Java8,应该是“数组+链表/红黑树”的方式,默认阈值为树化8退化6

 === 线程安全:
HashMap是不安全,JDK1.8-并发由于插入采用的是头插法可能会导致
 环形链,JDK1.8+插入数据采用的是尾插法可能会导致数据丢失。集合框架中有两种
线程安全的实现Collections.synchronizedMap(new java.util.HashMap<>())和
juc包中的ConcurrentHashMap,前者是锁整个表,后者采用乐观锁的方式

 ===性能特点:
HashMap可以在常数时间内增加,删除,查找元素,但这也是一种平均
 情况,使用load factor装载因子计算阈值就是为了减少冲突带来的性能退化

=== 扩容方法:
HashMap的桶数组一次扩展为原数组的2倍,控制扩展和移动的次数,
这里需要执行rehash计算。如果容量小于64只会进行简单扩容,如果容量大于64
则会进行树化改造。树化处理可以避免哈希碰撞攻击。

===HashMap 与 HashTable区别:
1. 线程安全:HashMap是非线程安全的,HashTable是线程安全的;HashTable内部的方法基本都经过
synchronized修饰。(如果要保证线程安全的话就使用ConcurrentHashMap)

 2. 效率:因为线程安全的问题,HashMap要比HashTable效率高一点。另外HashTable基本被淘汰,不要在代码中使用它

 3. 对Null key和Null value的支持:HashMap中null可以作为键,这样的键只有一个,可以有一个或多个键所对应的值为null。但是在HashTable中put进的键值只要有一个null,直接抛
 NullPointerException

4. 初始容量大小和每次扩充容量大小的不同 :
        创建时如果不指定容量初始值,Hashtable默认的初始大小为11,之后每次扩充,容量变为原来的 2n+1。HashMap默认的初始化大小为16。之后每次扩充,容量变为原来的2倍。创建时如果给定了容量初始值,那么Hashtable会直接使用给定的大小,而HashMap会将其扩充为
2的幂次方大小。也就是说HashMap总是使用2的幂作为哈希表的大小。

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

6. 推荐使用:在Hashtable的类注释可以看到,Hashtable是保留类不建议使用,推荐在单线程环境下使 用HashMap替代,如果需要多线程使用则用ConcurrentHashMap替代。

Tree Map总结:

===Tree Map概述
​ TreeMap是Map接口的一个实现类,可以实现存储元素的自动排序。在TreeMap中,键值对之间按键有序,TreeMap的实现基础是平衡二叉树,也称红黑树。使用红黑树存储元素,可以保证元素按key值的大小进行遍历。

=== 构造函数
TreeMap():无参的空构造函数,所有键插入有序。
TreeMap(Comparator<? super K> comparator):指定元素排序所用的比较器,key排列顺序由比较器指定。
TreeMap(Map<? extends K, ? extends V> m):用指定Map填充TreeMap,所有键按照自然排序。
TreeMap(SortedMap<K,? extends V> m):该TreeMap包含与指定的SortedMap相同的映射,并使用相同的顺序。

===红黑树的特性:
(1)每个节点或者是黑色,或者是红色。
(2)根节点是黑色。
(3)每个叶子节点(NIL)是黑色。(注意:这里叶子节点,是指为空(NIL或NULL)的叶子节点!)
(4)如果一个节点是红色的,则它的子节点必须是黑色的。
(5)从一个节点到该节点的子孙节点的所有路径上包含相同数目的黑节点。

===叶子节点,根节点,子节点:

所谓的树形结构就是各个元素之间具有分层关系的数据结构,常用一棵倒置的树来表示逻辑关系。
所谓的根节点就是树的最顶端的节点,
继续往下分为子节点,
当不断细分直到不再有子节点时为叶子节点。

注意:
《《《《《TreeMap必须要继承Comparator 或者Comparable 并重写里面的compare或者compareTo方法》》》》

===TreeMap的特性:

(1)TreeMap的存储结构只有一颗红黑树;

(2)TreeMap中的元素是有序的,按key的顺序排列;

(3)TreeMap比HashMap要慢一些,因为HashMap前面还做了一层桶,寻找元素要快很多

(4)TreeMap没有扩容的概念;

(5)TreeMap的遍历不是采用传统的递归式遍历;

(6)TreeMap可以按范围查找元素,查找最近的元素;

===如何选择合适的Map:
HashMap可实现快速存储和检索,但其缺点是其包含的元素是无序的,这导致它在存在大量迭代的情况下表现不佳。
LinkedHashMap保留了HashMap的优势,且其包含的元素是有序的。它在有大量迭代的情况下表现更好。
TreeMap能便捷的实现对其内部元素的各种排序,但其一般性能比前两种map差。
LinkedHashMap映射减少了HashMap排序中的混乱,且不会导致TreeMap的性能损失。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值