在Effective Java中的第九条说:覆盖equals总要覆盖hashCode。
“一个很常见的错误根源在于没有覆盖hashCode方法,在每个覆盖了equals方法的类中,也必须覆盖hashCode方法。”
以下约定内容摘自Object规范[JavaSE6]:
1. 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,
必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。
2.
如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
3. 如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不 要求一定生成不同的整数结果。但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。
显然,如果没有覆盖hashCode,就会违反第二条关键约定。
以上为理论部分,以下为实际实践的尝试,显示hashCode的作用:
首先生成一个简单的Box类:
public final class Box {
private int length;
private int width;
private int heigth;
public Box(){
}
public Box(int length, int width, int heigth){
this.length = length;
this.width = width;
this.heigth = heigth;
}
public int getLength() {
return length;
}
public void setLength(int length) {
this.length = length;
}
public int getWidth() {
return width;
}
public void setWidth(int width) {
this.width = width;
}
public int getHeigth() {
return heigth;
}
public void setHeigth(int heigth) {
this.heigth = heigth;
}
@Override
//重写equals方法。
public boolean equals(Object o){
if(o == this){
return true;
}else if(!(o instanceof Box)){
return false;
}else {
Box boxtmp = (Box) o;
return boxtmp.heigth == this.heigth
&& boxtmp.width == this.width
&& boxtmp.length == this.length;
}
}
}
类Box中重写了equals方法。
然后写一个测试类:
iimport java.util.HashMap;
public class HashCodeAndEqualTest {
public static void main(String[] args) {
Map<Box, Integer> map = new HashMap<Box, Integer>();
Box a = new Box(1,2,3);
Box b = new Box(1,2,3);
System.out.println("a == b :"+(a == b));
System.out.println("a .equals(b):"+a .equals(b));
map.put(a, 1);
System.out.println(map.get(a));
System.out.println(map.get(b));
}
}
输出结果:
引用
a == b :false
a .equals(b):true
1
null
既然a.equals(b)都已经为true了,那为什么map.get(b)的返回值为null呢?map.get(b)的预期值应该和map.get(a)相等的,下面再在Box类中重写一个父类方法:hashCode():
@Override
public int hashCode(){
int result = 0;
result = result * 31 + length;
result = result * 31 + heigth;
result = result * 31 + width;
return result;
}
然后再运行测试类,结果如下:
a == b :false
a .equals(b):true
1
1
为什么这次map.get(b) 和map.get(a)中的值相等了呢?这是因为重写了Box类中的hashCode方法,符合了第二天规定,
如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。
这样对象a和对象b的hash值是相等的。通俗一点儿讲, 如果a.hashCode () = b.hashCode()而且 a.euqals(b) (或 a==b) , 那么根据HashMap的算法,二者在同一个位置的,即HashMap认为只有符合以上条件,才认为a,和b是为同一key。
再深一点儿,可以参考HashMap中的get和put方法的实现,便可一探究竟。
HashMap中的get方法:
public V get(Object key) {
if (key == null)
return getForNullKey();
int hash = hash(key.hashCode());
for (Entry<K,V> e = table[indexFor(hash, table.length)];
e != null;
e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
return e.value;
}
return null;
}
HashMap中的put方法:
public V put(K key, V value) {
if (key == null)
return putForNullKey(value);
int hash = hash(key.hashCode());
int i = indexFor(hash, table.length);
for (Entry<K,V> e = table[i]; e != null; e = e.next) {
Object k;
if (e.hash == hash && ((k = e.key) == key || key.equals(k))) {
V oldValue = e.value;
e.value = value;
e.recordAccess(this);
return oldValue;
}
}
modCount++;
addEntry(hash, key, value, i);
return null;
}
if (e.hash == hash && ((k = e.key) == key || key.equals(k)))
这一句已经大致解释了刚才的情况,更深一点儿可以探究一下hash算法的实现,挺有意思,不过时间有限,就先写到这里了~~
分享到:
相关推荐
主要介绍了Java 覆盖equals时总要覆盖hashcode的相关资料,这里附有实例代码,具有参考价值,需要的朋友可以参考下
Java重写equals同时需要重写hashCode的代码说明,以及如何重写hashCode方法,此代码演示按照effective java书籍说明的重写思路。代码中演示了使用集合存储对象,并且对象作为key,需重写equals和hashCode.
解析Java对象的equals()和hashCode()的使用
本文介绍了Java语言不直接支持关联数组,可以使用任何对象作为一个索引的数组,但在根Object类中使用 hashCode()方法明确表示期望广泛使用HashMap。理想情况下基于散列的容器提供有效插入和有效检索;直接在对象模式...
NULL 博文链接:https://zpointer.iteye.com/blog/1058337
equals()和hashcode()这两个方法都是从object类中继承过来的。当String 、Math、还有Integer、Double。。。。等这些封装类在使用equals()方法时,已经覆盖了object类的equals()方法.
Java中的equals()和hashCode()契约Java开发Java经验技巧共3页.pdf.zip
这里是一个文档,里边讲解了hashCode与equals方法使用,大家要是不明白,可以去看看
重写equals和hashcode方法,学习和进步
2、为什么改写equals()的时候,总是要改写hashCode() 两个原则: hashCode()的返回值和equals()的关系如下: 如果x.equals(y)返回“true”,那么x和y的hashCode()必须相等。 如果x.equals(y)返回...
主要介绍了探索Java中的equals()和hashCode()方法的相关资料,需要的朋友可以参考下
关于hashCode()和equals()的本质区别和联系.doc
本文中详细的阐述了Java中经常遇到的equals、hashcode以及“==”号三者之间的区别
equals():反映的是对象或变量具体的值,即两个对象里面包含的值--可能是对象的引用,也可能是值类型的值。 hashCode():计算出对象实例的...当然,当对象所对应的类重写了hashCode()方法时,结果就截然不同了。
更清楚的了解hashcode()和equals()方法。
java中hashcode和equals的详解.pdf
如果一个类的hashCode()方法没有遵循上述要求,那么,当这个类的两个实例对象用equals()方法比较的结果相等时,他们本来应该无法被同时存储进set集合
Java equals 方法与hashcode 方法的深入解析.rar
超详细_解释java_equals()与hashCode().pdf