概述
接下来我们要讨论如下问题:
1、Set接口的contains
方法,判断是否包含的依据是什么?
2、对象hashCode
和equals
方法之间的关系
1、Set接口的contains
方法,判断是否包含的依据是什么?
我查看了一下接口文档,里面是这样描述的:
该方法重写了Collection
接口的contains
方法
Returns true if this set contains the specified element. More formally, returns true if and only if this set contains an element e such that (o == null ? e==null : o.equals(e)).
也就是说,当且仅当
1:参数o,如果o为空,set中也有空时
2:参数o.equals(e),e为set中的一个元素
上述两种情况,会返回true。
2、对象hashCode
和equals
方法之间的关系
同样,阅读接口文档,equals
方法说明如下:
Note that it is generally necessary to override the hashCode method whenever this method is overridden, so as to maintain the general contract for the hashCode method, which states that equal objects must have equal hash codes
就是说,如果一个对象重写了equals
方法,通常也需要重写hashCode
方法。根据契约约定,如果两个对象相等,则它们的hash值必须相等。
换句话说,如果两个对象的hash值不同,则调用它们的.equals
去比较,肯定返回false
。
阅读hashCode
的文档说明:
If two objects are equal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce the same integer result.
如果两个对象相等,则必须返回相等的hash值。这和equals
说明一致。
It is not required that if two objects are unequal according to the equals(Object) method, then calling the hashCode method on each of the two objects must produce distinct integer results. However, the programmer should be aware that producing distinct integer results for unequal objects may improve the performance of hash tables.
简单的说,如果两个对象不相等,它们的hash值可能相等。
所以,不能认为hash值一样,就说两个对象相等。
As much as is reasonably practical, the hashCode method defined by class Object does return distinct integers for distinct objects. (This is typically implemented by converting the internal address of the object into an integer, but this implementation technique is not required by the JavaTM programming language.)
通常,不同对象还是需要返回不同的hash值。通常是通过将对象的内部地址转换为integer实现的。
代码验证
我自定义一个Dog对象,先不重写equals
和hashCode
,当Set中添加了两个白色的狗对象时,我们用contains
方法去校验Set中是否包含白色的狗对象,会得到如下结果:
import java.util.HashSet;
import java.util.Set;
/**
* created at 2018-10-08 17:24
* @author lerry
*/
class Dog {
String color;
public Dog(String s) {
color = s;
}
}
public class SetAndHashCode {
public static void main(String[] args) {
Set<Dog> dogSet = new HashSet<>();
dogSet.add(new Dog("white"));
dogSet.add(new Dog("white"));
System.out.printf("we have %d white dogs", dogSet.size());
System.out.println();
if (dogSet.contains(new Dog("white"))) {
System.out.println("Set has white dog!");
}
else {
System.out.println("Set don't have white dog!");
}
}
}
/*
console results:
we have 2 white dogs
Set don't have white dog!
*/
这说明:
默认new一个新对象,会产生新的hash值。
可以验证一下:
public class SetAndHashCode {
public static void main(String[] args) {
System.out.println(new Dog("white").hashCode());
System.out.println(new Dog("white").hashCode());
}
}
/*
console results:
2000502626
704603837
*/
接下来,我们重新Dog类的equals
方法,让类认为只要颜色一样,就算相等:
class Dog {
String color;
public Dog(String s) {
color = s;
}
public String getColor() {
return color;
}
@Override
public boolean equals(Object obj) {
if (obj instanceof Dog && this.color.equals(((Dog) obj).getColor())) {
return true;
}
else {
return false;
}
}
}
public class SetAndHashCode {
public static void main(String[] args) {
Set<Dog> dogSet = new HashSet<>();
dogSet.add(new Dog("white"));
dogSet.add(new Dog("white"));
System.out.printf("we have %d white dogs", dogSet.size());
System.out.println();
if (dogSet.contains(new Dog("white"))) {
System.out.println("Set has white dog!");
}
else {
System.out.println("Set don't have white dog!");
}
}
}
/*
console results:
we have 2 white dogs
Set don't have white dog!
*/
但是结果并没有什么改变。对了,根据如果两个对象相等,则它们的hash值必须相等
原则,我们还应该去重写hashCode
方法:
@Override
public int hashCode() {
return this.color.hashCode();
}
这时,控制台返回的结果终于变成了:
we have 1 white dogs
Set has white dog!
Set对重复元素,进行了去重。所以,添加了两次
dogSet.add(new Dog("white"));
dogSet.add(new Dog("white"));
后,dogSet.size()
依旧为1
。
参考
Java中hashCode与equals方法的约定及重写原则
jdk api
代码环境描述
jdk 1.7
macOS 10.13.4