前言
本文正在参加「Java主题月 - Java Debug笔记活动」,详情查看 活动链接
直接进入正题,hashCode
方法和equals
方法
hashCode
public native int hashCode();
hashCode
方法用来获取当前对象的哈希码
,也称为散列码
,本质上是一个int类型的整数。哈希码的作用是确定该对象在我们常见的Java集合中如HashMap
,Hashtable
,HashSet
中的位置,每个对象对应的hashCode
不一样,避免在集合类中进行存放时出现hash
碰撞
equals
public boolean equals(Object obj) {
return (this == obj);
}
默认equals
方法的实现为直接对象两个对象的是否在内存中为同一个对象,在我们日常开发中,使用equals方法更多的是判断两个对象是否相等
,而非是同一个对象,所以会重写equals
方法,如Integer
中,equals
方法对比的是对应包装的基本类型int
的值,同样Integer
中也重写了hashCode
方法,保证相同
对象返回的hashCode
也保持一致
public boolean equals(Object obj) {
if (obj instanceof Integer) {
return value == ((Integer)obj).intValue();
}
return false;
}
@Override
public int hashCode() {
return Integer.hashCode(value);
}
public static int hashCode(int value) {
return value;
}
那为什么要在重写equals
的同时,重写hashCode
方法呢,或者更加准确地说,为什么在重写equals
方法的同时,重写hashCode
方法来保证equals
方法结果为true
时,hashCode
也相等呢
本质上,当两个对象相等时,在散列表
中的位置应当是一致的,而在散列表中,计算对象存放位置的方式就是通过hash
算法计算对象的hashCode
得到hash
值,如HashMap
中,设置kv
时,需要先计算hash
值来确认槽位,hash
值则通过hashCode
运算得到
public V put(K key, V value) {
return putVal(hash(key), key, value, false, true);
}
static final int hash(Object key) {
int h;
return (key == null) ? 0 : (h = key.hashCode()) ^ (h >>> 16);
}
同样在获取对应值时,则先通过hash
值进行槽定位获取,当计算的hash
值不相同时,就可能出现put
进去数据但获取不到的尴尬结果
public V get(Object key) {
Node<K,V> e;
return (e = getNode(hash(key), key)) == null ? null : e.value;
}
同时,计算hashCode要避免变量性强的字段,当hashCode的计算涉及到某些变量时,改变变量的值后,可能就取不出来了
@Data
public class Data implements Serializable {
private Integer id;
public boolean equals(Object obj) {
if(obj instanceof Data){
Data obj1 = (Data) obj;
return obj1.id == this.id;
}
return false;
}
@Override
public int hashCode() {
return id+1;
}
}
public static void main(String[] args) {
Data data = new Data();
data.setId(1);
Map<Data, Integer> map = new HashMap<>();
map.put(data,1);
System.out.println(map.get(data));
data.setId(2);
System.out.println(map.get(data));
}
输出结果为
1
null