== 号是运算符,equals来自于object定义的一个方法;
== 可以用于基本数据类型和引用数据类型,equals只能用于引用类型;
== 两端如果是基本数据类型,比较的值;
equals重写之后,判断两个对象的属性值是否相同;
equals不重写,其实就是==号;
重写equals可以让我们自己定义判断两个对象是否相同的条件;
Object中定义的hashCode方法生成的哈希码能保证同一个对象的哈希码一定是不同的;
当equals返回为true,我们在逻辑上可以认为是同一个对象,但是查看哈希码发现不同,和equals方法的返回结果违背;
Object中定义的hashCode方法生成的哈希码跟对象的本身属性值无关;
重写hashCode后可以自定义hash码的生成规则;可以通过对象的属性值计算出哈希码;
hashMap中,借助 equals 和 hashCode 来完成这个数据的存储;
将根据对象的内容查询转换为索引查询;
java1.7 hashMap的数据结构为数组+链表;
java1.8 hashMap的数据结构为数组+链表+红黑树;
java1.7中,插入链表节点使用头插法。java1.8中变成了尾插法。
java1.8的hash中;将hash值高位(前16位)参与到取模的运算中,使得计算结果的不确定性增强,降低发生哈希碰撞的概率;
扩容优化:
1.7对元素进行rehash算法,计算原来的每个元素在扩容之后的哈希表的位置;
1.8通过高位运算(e.hash & oldCap)来确定元素是否需要移动,比如key1 的信息如下:
key1.hash = 10 0000 1010
oldCap = 16 0001 0000
使用e.hash & oldCap 得到的结果,高一位为0,当结果为0时表示元素在扩容时位置不会发生任何变化,为1时位置发生变化,新下标位置等于 原下标位置 + 原数组长度 hashmap,无需重新计算下标位置。
方式一:通过Collections.synchonizedMap()返回一个新的Map,这个新的map就是线程安全的。
特点:
1)使用了经典的synchronized来进行互斥;
2)使用了代理模式,创建了一个新的类,这个类同样实习map接口;
优点:代码实现简单,一看就懂;缺点:从锁的角度来看,方法一直使用了锁住方法,性能较差。
方式二:ConcurrentHashMap
1.7 为分段锁,1.8 CAS尝试失败了在加锁。
优点:需要互斥的代码比较少,性能会比较好,把整个hashmap分为多个块,发生锁碰撞的概率大大降低,性能会比较好。缺点:代码比较繁琐
4、为什么hashmap扩容的时候是两倍?
1.8扩容之后,重新确认元素位置,和原来的hash标进行高位运算。
降低哈希冲突;
当hashMap的容量是16时,他的二进制是10000,(n-1)01111,与hash计算结果很少重复;
当hashmap的容量不是2的n次幂的情况,会出现严重hash冲突;
平衡二叉树类型 | 介绍 | 平衡度 | 调整频率 | 适用场景 |
---|---|---|---|---|
AVL树 | 任何节点的两个子树的高度最大差别为1 | 高 | 高 | 查询多,增/删少 |
红黑树 | 任何节点的两个子树的高度最大差别为2倍 | 低 | 低 | 增/删频繁 |