hashcode与equals的缘分
Posted 朱洪昌
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了hashcode与equals的缘分相关的知识,希望对你有一定的参考价值。
重写equals方法必须重写hashCode方法?
看jdk的api怎么说?
hashCode public int hashCode()
返回该对象的哈希码值。支持此方法是为了提高哈希表(例如 java.util.Hashtable 提供的哈希表)的性能。
hashCode 的常规协定是: 在 Java 应用程序执行期间,在对同一对象多次调用 hashCode 方法时,必须一致地返回相同的整数,前提是将对象进行 equals 比较时所用的信息没有被修改。
从某一应用程序的一次执行到同一应用程序的另一次执行,该整数无需保持一致。 如果根据 equals(Object) 方法,两个对象是相等的,那么对这两个对象中的每个对象调用 hashCode 方法都必须生成相同的整数结果。 如果根据 equals(java.lang.Object) 方法,两个对象不相等,那么对这两个对象中的任一对象上调用 hashCode 方法不要求一定生成不同的整数结果。
但是,程序员应该意识到,为不相等的对象生成不同整数结果可以提高哈希表的性能。 实际上,由 Object 类定义的 hashCode 方法确实会针对不同的对象返回不同的整数。
(这一般是通过将该对象的内部地址转换成一个整数来实现的,但是 JavaTM 编程语言不需要这种实现技巧。) equals public boolean equals(Object obj) 指示其他某个对象是否与此对象“相等”。 equals 方法在非空对象引用上实现相等关系: 自反性:对于任何非空引用值 x,x.equals(x) 都应返回 true。 对称性:对于任何非空引用值 x 和 y,当且仅当 y.equals(x) 返回 true 时,x.equals(y) 才应返回 true。 传递性:对于任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,并且 y.equals(z) 返回 true,那么 x.equals(z) 应返回 true。 一致性:对于任何非空引用值 x 和 y,多次调用 x.equals(y) 始终返回 true 或始终返回 false,前提是对象上 equals 比较中所用的信息没有被修改。 对于任何非空引用值 x,x.equals(null) 都应返回 false。 Object 类的 equals 方法实现对象上差别可能性最大的相等关系;
即,对于任何非空引用值 x 和 y,当且仅当 x 和 y 引用同一个对象时,此方法才返回 true(x == y 具有值 true)。 注意:当此方法被重写时,通常有必要重写 hashCode 方法,以维护 hashCode 方法的常规协定,该协定声明相等对象必须具有相等的哈希码。
如果不重写equals,那么比较的将是对象的引用是否指向同一块内存地址,重写之后目的是为了比较两个对象的value值是否相等。特别指出利用equals比较八大包装对象
(如int,float等)和String类(因为该类已重写了equals和hashcode方法)对象时,默认比较的是值,在比较其它自定义对象时都是比较的引用地址
hashcode是用于散列数据的快速存取,如利用HashSet/HashMap/Hashtable类来存储数据时,都是根据存储对象的hashcode值来进行判断是否相同的。
这样如果我们对一个对象重写了euqals,意思是只要对象的成员变量值都相等那么euqals就等于true,但不重写hashcode,那么我们再new一个新的对象,
当原对象.equals(新对象)等于true时,两者的hashcode却是不一样的,由此将产生了理解的不一致,
如在存储散列集合时(如Set类),将会存储了两个值一样的对象,导致混淆,因此,就也需要重写hashcode()
举个例子:(转载自:http://www.jianshu.com/p/75d9c2c3d0c1)
public class HashMapTest { private Integer a; public HashMapTest(int a) { this.a = a; } public static void main(String[] args) { Map<HashMapTest, Integer> map = new HashMap<HashMapTest, Integer>(); HashMapTest instance = new HashMapTest(1); HashMapTest newInstance = new HashMapTest(1); map.put(instance, 1); map.put(newInstance, 2); Integer value = map.get(instance); System.out.println("instance value:"+value); Integer value1 = map.get(newInstance); System.out.println("newInstance value:"+value1); } public boolean equals(Object o) { if(o == this) { return true; } else if(!(o instanceof HashMapTest)) { return false; } else { HashMapTest other = (HashMapTest)o; if(!other.canEqual(this)) { return false; } else { Integer this$data = this.getA(); Integer other$data = other.getA(); if(this$data == null) { if(other$data != null) { return false; } } else if(!this$data.equals(other$data)) { return false; } return true; } } } protected boolean canEqual(Object other) { return other instanceof HashMapTest; } public void setA(Integer a) { this.a = a; } public Integer getA() { return a; } } //运行结果: //instance value:1 //newInstance value:2
??你会发现,不对呀?同样的一个对象,为什么在map中存了2份,map的key值不是不能重复的么?没错,它就是存的2份,只不过在它看来,这2个的key是不一样的,因为他们的哈希码就是不一样的,可以自己测试下,上面打印的hash码确实不一样。那怎么办?只有重写hashCode()方法,更改后的代码如下:
public class HashMapTest { private Integer a; public HashMapTest(int a) { this.a = a; } public static void main(String[] args) { Map<HashMapTest, Integer> map = new HashMap<HashMapTest, Integer>(); HashMapTest instance = new HashMapTest(1); System.out.println("instance.hashcode:" + instance.hashCode()); HashMapTest newInstance = new HashMapTest(1); System.out.println("newInstance.hashcode:" + newInstance.hashCode()); map.put(instance, 1); map.put(newInstance, 2); Integer value = map.get(instance); System.out.println("instance value:"+value); Integer value1 = map.get(newInstance); System.out.println("newInstance value:"+value1); } public boolean equals(Object o) { if(o == this) { return true; } else if(!(o instanceof HashMapTest)) { return false; } else { HashMapTest other = (HashMapTest)o; if(!other.canEqual(this)) { return false; } else { Integer this$data = this.getA(); Integer other$data = other.getA(); if(this$data == null) { if(other$data != null) { return false; } } else if(!this$data.equals(other$data)) { return false; } return true; } } } protected boolean canEqual(Object other) { return other instanceof HashMapTest; } public void setA(Integer a) { this.a = a; } public Integer getA() { return a; } public int hashCode() { boolean PRIME = true; byte result = 1; Integer $data = this.getA(); int result1 = result * 59 + ($data == null?43:$data.hashCode()); return result1; } } //运行结果: //instance.hashcode:60 //newInstance.hashcode:60 //instance value:2 //newInstance value:2
以上是关于hashcode与equals的缘分的主要内容,如果未能解决你的问题,请参考以下文章
Java equals 方法与hashcode 方法的深入解析