物件導向語言JAVA中,所有物件皆自動繼承名為『Object』的物件,包含了下例數種基本函數:
![](http://pic31.pic.wretch.cc/photos/20/b/bbkb/1/1137585326.jpg)
這些函數為所有JAVA物件中的共同函數,在撰寫程式時,常需覆寫(Override)其中某些函數,下列將簡單說明何種情況下,需覆寫物件中toString、equals和hashCode函數。
● toString的使用時機
假設物件Foo簡單地定義如下:
class Foo {
public final String name;
public final int age;
public Foo(String name,int age) {
this.name = name;
this.age = age;
}
}
若宣告foo1並印出:
Foo foo1 = new Foo("A",10);
System.out.println(foo1);
可能會得到下列的輸出結果:
Foo@1a7bf11
若希望輸出的資訊有意義,可覆寫toString函數,如:
class Foo {
public final String name;
public final int age;
public Foo(String name,int age) {
this.name = name;
this.age = age;
}
public String toString() {
return name + " " + age;
}
}
印出foo1會得到:
A 10
在未覆寫toString的情況下,呼叫println印出的foo資訊為JVM所給定此物件的識別碼,此識別碼對於程式人員並無幫助,而覆寫後,印出的物件資訊將由覆寫內容之程式碼決定,可增進除錯(Debug)時的效率。
● equals的使用時機
equals用於比較兩個物件是否相同,在這裡所謂的"equals"意義為內容上的相同,以上述的Foo物件舉例,若宣告並印出比較結果如下:
Foo foo1 = new Foo("A",10);
Foo foo2 = new Foo("A",10);
Foo foo3 = foo1;
System.out.println(foo1.equals(foo2) + " " + foo1.equals(foo3));
會印出
false true
Foo的equals函式未覆寫時,預設的equals函式執行動作,將比較兩個變數所在的記憶體位置是否相同,並未比對其實際內容,因此,將Foo中的equals函數覆寫,如:
class Foo {
public final String name;
public final int age;
public Foo(String name,int age) {
this.name = name;
this.age = age;
}
public String toString() {
return name + " " + age;
}
public boolean equals(Object obj) {
if (obj != null && obj instanceof Foo)
if (this.name != null && this.name.equals( ( (Foo) obj).name))
if (this.age == ( (Foo) obj).age)
return true;
return false;
}
}
equals函數標準的覆寫方法為public boolean equals(Object obj),引數obj型態為Object,所以在equals內,需檢查obj的型態是否為Foo,並比對兩物件之name和age,其中因name的型態為String,比對時需使用String物件已覆寫之equals函式進行檢查,確保this.name和obj.name的內容一致。
‧hashCode的使用時機
hashCode(雜湊碼)代表了一個物件的編碼,常用於物件的比較上,JAVA中的每個物件皆繼承了預設的hashCode函數,但若兩個相同內容的物件卻分別位於不同的記憶體位置,以預設的hashCode函數編碼結果不保證一致,若希望僅以物件的內容進行編碼,需覆寫hashCode函數。
在JDK的java.util套件中,包含了常用的集合(Set)或樹(Tree)資料結構,Set中常用到的有TreeSet及HashSet ,HashSet常用於儲存並且篩選重複物件,以上述所提及Foo物件為例:
class Foo {
public final String name;
public final int age;
public Foo(String name,int age) {
this.name = name;
this.age = age;
}
}
若不覆寫hashCode及equals的情況下,希望相同內容的物件不會加入HashSet:
Foo foo1 = new Foo("A",20);
Foo foo2 = new Foo("A",20);
Foo foo3 = foo1;
HashSet hs = new HashSet();
hs.add(foo1);
System.out.println(hs.size());
hs.add(foo2);
System.out.println(hs.size());
hs.add(foo3);
System.out.println(hs.size());
會印出
1
2
2
在物件HashSet中,將物件加入HashSet前需經過檢查,確保Set中不會有重複的物件出現,呼叫函數add時,此函數首先呼叫傳入物件的hashCode,並與HashSet中每個已加入物件的hashCode比對,若某個HashSet中的物件之hashCode與傳入物件一致,再以equals函式比對兩者是否一致,因此加入foo2時,HashSet將foo2及foo1視為不同的物件,使得foo2被加入HashSet。
欲修正此問題,僅需覆寫equals及hashCode如:
class Foo {
public final String name;
public final int age;
public Foo(String name,int age) {
this.name = name;
this.age = age;
}
public boolean equals(Object obj) {
if (obj != null && obj instanceof Foo)
if (this.name != null && this.name.equals( ( (Foo) obj).name))
if (this.age == ( (Foo) obj).age)
return true;
return false;
}
public int hashCode() {
return name.hashCode() << (age % 8) * age;
}
}
執行上述程式碼,會得到:
1
1
1
由輸出結果可知,HashSet中僅加入了foo1物件,並將foo2與foo3視為與foo1一致,所以HashSet大小為1,如此一來可確保HashSet中不會有重複內容的物件出現。
全站熱搜