HashCode和HashMap
1.HashCode
java.lang.Object类中有两个非常重要的方法:
public boolean equals(Object obj)
public int hashCode()
Object类是类继承结构的基础,所以是每一个类的父类。所有的对象,包括数组,都实现了在Object类中定义的方法。
equals()方法是用来判断其他的对象是否和该对象相等.
equals()方法在object类中定义如下:
public boolean equals(Object obj) {
return (this == obj);
}
很明显是对两个对象的地址值进行的比较(即比较引用是否相同)。但是我们知道,String 、Math、Integer、Double等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法。
hashcode() 方法
hashCode()
方法给对象返回一个hash code值。这个方法被用于hash tables,例如HashMap。
简而言之,在集合查找时,hashcode能大大降低对象比较次数,提高查找效率!
Java对象的eqauls方法和hashCode方法是这样规定的:
1、相等相同)的对象必须具有相等的哈希码(或者散列码)。
2、如果两个对象的hashCode相同,它们并不一定相同。
Hashset、Hashmap、Hashtable与hashcode()和equals()的密切关系
- Hashset
- 在hashset中不允许出现重复对象,元素的位置也是不确定的
- 1.判断两个对象的hashCode是否相等 如果不相等,认为两个对象也不相等,如果相等,转入2
- 2.判断两个对象用equals运算是否相等
2.HashMap
哈希桶 基于int hashCode实现
- 核心是基于哈希值的桶和链表
- O(1)的平均查找、插入、删除时间
- 将元素映射成hash值
- 底层是数组,数值查找值是常数时间,O(1)
- 多个元素hash值相同,数据发生了碰撞,会有链表。 哈希值的碰撞是致命缺陷。
Java7 经典实现
hashcode->(0,n-1)
- 取模
- 负数取模是负数,无法存
- 速度较慢
- 为什么初始化是16,扩容是两倍。按位与,只有长度是2的n次方,只有len-1之后才可以是1111,按位与之后才可以拿到数组下标,而且分布均匀。
resize里的问题根源
java7 hashmap的问题
- hashmap死锁,线程不安全。经典的数组+链表。同时入桶的话,会产生环链表。所以是线程不安全的。
- String有可能hashcode相同,所以存入hashmap的时候产生链表,非常慢。伪造恶意请求引发Dos错误。
- jdk1.7中,如果是String,则用新的hash算法H
java8 hashmap的改进
treeify 8 阈值
hash算法
- 高位不同,低位相同
- 异或不进位的加法
- 线程不安全是由于扩容问题。
- newIndex 要么相等,要么最高位加1.重新计算hash值就是拆分成两个新的链表。重新复制到新的hash桶里
- resize效率非常低。Resize效率很低,因为每次都要