定義差別
- equals() :
- hashCode():
- 作用是擷取哈希碼,也稱為散列碼;
- 它實際上是傳回一個 int 整數。
- 這個哈希碼的作用是确定對象在哈希表中的索引位置。
一個類本身不建立散清單
- 該類的 hashCode() 和 equals() 沒有關系,equals() 用來比較該類的兩個對象是否相等,而 hashCode() 則根本沒有任何作用。
- equals() 相等的情況下,hashCode() 也不一定相等。
/**
* @desc 比較equals()傳回true和傳回false時,hashCode()的值。
*/
public class NormalHashCodeTest{
public static void main(String[] args) {
// 建立2個相同内容的Person對象,
// 再用equals比較它們是否相等
Person p1 = new Person("eee", 100);
Person p2 = new Person("eee", 100);
Person p3 = new Person("aaa", 200);
System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode());
System.out.printf("p1.equals(p3) : %s; p1(%d) p3(%d)\n", p1.equals(p3), p1.hashCode(), p3.hashCode());
}
/* Person類 */
private static class Person {
int age;
String name;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return name + " - " +age;
}
/* 覆寫equals方法 */
public boolean equals(Object obj){
if(obj == null){
return false;
}
//如果是同一個對象傳回true,反之傳回false
if(this == obj){
return true;
}
//判斷是否類型相同
if(this.getClass() != obj.getClass()){
return false;
}
/* 比較name和age的值 */
Person person = (Person)obj;
return name.equals(person.name) && age==person.age;
}
}
}
p1.equals(p2) : true; p1(1169863946) p2(1901116749)
p1.equals(p3) : false; p1(1169863946) p3(2131949076)
- 從結果也可以看出:p1 和 p2 相等的情況下,hashCode() 也不一定相等。
一個類本身會建立散清單
- 該類的 hashCode() 和 equals() 是有關系的。比如 HashSet, Hashtable, HashMap 等等
- 如果兩個對象相等,那麼它們的 hashCode() 一定相等。這裡的相等是指,通過equals()比較兩個對象時傳回true。
- 如果兩個對象 hashCode() 相等,但它們并不一定相等。因為在散清單中,hashCode()相等,即兩個鍵值對的哈希值相等。然而哈希值相等,并不一定能得出鍵值對相等。補充說一句:“兩個不同的鍵值對,哈希值相等”,這就是哈希沖突。
- 在這種情況下。若要判斷兩個對象是否相等,除了要覆寫 equals() 之外,也要覆寫hashCode() 函數。否則,equals() 無效。
- 舉例
- 建立 Person 類的 HashSet 集合,必須同時覆寫 Person 類的 equals() 和 hashCode() 方法。
- 隻是覆寫 equals() 方法
- 我們會發現,equals() 方法沒有達到我們想要的效果。
import java.util.*;
import java.lang.Comparable;
/**
* @desc 比較equals() 傳回true 以及 傳回false時, hashCode()的值。
*
*/
public class ConflictHashCodeTest1{
public static void main(String[] args) {
// 建立Person對象,
Person p1 = new Person("eee", 100);
Person p2 = new Person("eee", 100);
Person p3 = new Person("aaa", 200);
// 建立HashSet對象
HashSet set = new HashSet();
set.add(p1);
set.add(p2);
set.add(p3);
// 比較p1 和 p2, 并列印它們的hashCode()
System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode());
// 列印set
System.out.printf("set:%s\n", set);
}
/**
* @desc Person類。
*/
private static class Person {
int age;
String name;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return "("+name + ", " +age+")";
}
/**
* @desc 覆寫equals方法
*/
@Override
public boolean equals(Object obj){
if(obj == null){
return false;
}
//如果是同一個對象傳回true,反之傳回false
if(this == obj){
return true;
}
//判斷是否類型相同
if(this.getClass() != obj.getClass()){
return false;
}
Person person = (Person)obj;
return name.equals(person.name) && age==person.age;
}
}
}
p1.equals(p2) : true; p1(1169863946) p2(1690552137)
set:[(eee, 100), (eee, 100), (aaa, 200)]
- 我們重寫了Person的equals()。但是,很奇怪的發現:HashSet中仍然有重複元素:p1 和 p2。為什麼會出現這種情況呢?
- 這是因為雖然 p1 和 p2 的内容相等,但是它們的 hashCode() 不等;是以,HashSet 在添加 p1 和 p2 的時候,認為它們不相等。
同時覆寫 equals() 和 hashCode() 方法呢? import java.util.*;
import java.lang.Comparable;
/**
* @desc 比較equals() 傳回true 以及 傳回false時, hashCode()的值。
*
*/
public class ConflictHashCodeTest2{
public static void main(String[] args) {
// 建立Person對象,
Person p1 = new Person("eee", 100);
Person p2 = new Person("eee", 100);
Person p3 = new Person("aaa", 200);
Person p4 = new Person("EEE", 100);
// 建立HashSet對象
HashSet set = new HashSet();
set.add(p1);
set.add(p2);
set.add(p3);
// 比較p1 和 p2, 并列印它們的hashCode()
System.out.printf("p1.equals(p2) : %s; p1(%d) p2(%d)\n", p1.equals(p2), p1.hashCode(), p2.hashCode());
// 比較p1 和 p4, 并列印它們的hashCode()
System.out.printf("p1.equals(p4) : %s; p1(%d) p4(%d)\n", p1.equals(p4), p1.hashCode(), p4.hashCode());
// 列印set
System.out.printf("set:%s\n", set);
}
/**
* @desc Person類。
*/
private static class Person {
int age;
String name;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public String toString() {
return name + " - " +age;
}
/**
* @desc重寫hashCode
*/
@Override
public int hashCode(){
int nameHash = name.toUpperCase().hashCode();
return nameHash ^ age;
}
/**
* @desc 覆寫equals方法
*/
@Override
public boolean equals(Object obj){
if(obj == null){
return false;
}
//如果是同一個對象傳回true,反之傳回false
if(this == obj){
return true;
}
//判斷是否類型相同
if(this.getClass() != obj.getClass()){
return false;
}
Person person = (Person)obj;
return name.equals(person.name) && age==person.age;
}
}
}
p1.equals(p2) : true; p1(68545) p2(68545)
p1.equals(p4) : false; p1(68545) p4(68545)
set:[aaa - 200, eee - 100]
- 結果分析:
- 這下,equals() 生效了,HashSet 中沒有重複元素。
- 比較 p1 和 p2,我們發現:它們的 hashCode() 相等,通過 equals() 比較它們也傳回 true。是以,p1 和 p2 被視為相等。
- 比較 p1 和 p4,我們發現:雖然它們的 hashCode() 相等;但是,通過 equals() 比較它們傳回 false。是以,p1 和 p4 被視為不相等。