在您的代码中实现equals
方法时,必须同时实现(重写)hashCode
方法。这是您必须遵循的通用约定,以获得最佳性能。
以下是Joshua Bloch
的书《Effective Java》的摘录:
第9项: 在重写equals时总是要重写hashCode
A common source of bugs is the failure to override the hashCode method. You
must override hashCode in every class that overrides equals. Failure to do so
will result in a violation of the general contract for Object.hashCode, which will
prevent your class from functioning properly in conjunction with all hash-based
collections, including HashMap,HashSet, and Hashtable.
Here is the contract, copied from the Object specification [JavaSE6]:
• Whenever it is invoked on the same object more than once during an execution
of an application, the hashCode method must consistently return the
same integer, provided no information used in equals comparisons on the
object is modified. This integer need not remain consistent from one execution
of an application to another execution of the same application.
• 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.
就像Pablo所说的那样,如果你在equals
方法签名中使用除了Object
类以外的任何东西,你实际上并没有覆盖equals
方法,你的程序将无法按预期工作。
以这个小程序为例,它将一个List
复制到一个Set
(不能包含重复项)并打印新的集合。尝试用equals(Item obj)
替换equals(Object obj)
,看看运行程序时会发生什么。此外,注释掉hashCode()
方法并运行程序,观察使用和不使用它之间的差异。
public class Item {
private String name;
private double price;
private String countryOfProduction;
public Item(String name, double price, String countryOfProduction) {
this.setName(name);
this.setPrice(price);
this.setCountryOfProduction(countryOfProduction);
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public double getPrice() {
return price;
}
public void setPrice(double price) {
this.price = price;
}
public String getCountryOfProduction() {
return countryOfProduction;
}
public void setCountryOfProduction(String countryOfProduction) {
this.countryOfProduction = countryOfProduction;
}
public String toString() {
return "Item Name: " + getName() + "\n" +
"Item Price: N" + getPrice() + "\n" +
"Country of Production: " + getCountryOfProduction() + "\n";
}
@Override
public boolean equals(Object obj) {
if(!(obj instanceof Item)) {
return false;
}
if(obj == this) {
return true;
}
Item other = (Item)obj;
if(this.getName().equals(other.getName())
&& this.getPrice() == other.getPrice()
&& this.getCountryOfProduction().equals(other.countryOfProduction)) {
return true;
} else {
return false;
}
}
public int hashCode() {
int hash = 3;
hash = 7 * hash + this.getName().hashCode();
hash = 7 * hash + this.getCountryOfProduction().hashCode();
hash = 7 * hash + Double.valueOf(this.getPrice()).hashCode();
return hash;
}
public static void main (String[]args) {
List<Item> items = new ArrayList<>();
items.add(new Item("Baseball bat", 45, "United States"));
items.add(new Item("BLUESEAL Vaseline", 1500, "South Africa"));
items.add(new Item("BLUESEAL Vaseline", 1500, "South Africa"));
Collection<Item> noDups = new HashSet<>(items);
noDups.stream()
.forEach(System.out::println);
}
}