考慮下面的程序抽米,類Bigram 表示一個雙字母組,考慮打印語句的輸出結(jié)果
package thirtysix;
import java.util.HashSet;
import java.util.Set;
/**
* Bigram
* @author ZHAIYANMING
* @version 1.0
*
*/
public class Bigram {
private final char first;
private final char second;
public Bigram(char first, char second) {
this.first = first;
this.second = second;
}
public boolean equals(Bigram bigram) {
return bigram.first == first && bigram.second == second;
}
public int hashCode() {
return 31 * first + second;
}
public static void main(String[] args) {
Set<Bigram> bigrams = new HashSet<Bigram>();
for (int i = 0; i < 10; i++) {
for (char ch = 'a'; ch <= 'z'; ch++) {
bigrams.add(new Bigram(ch, ch));
}
}
System.out.println(bigrams.size());
}
}
為什么結(jié)果是這樣糙置?bigrams采用的集合類型是HashSet,為什么沒有去掉重復(fù)的元素呢云茸?
/**
* Adds the specified element to this set if it is not already present.
* More formally, adds the specified element <tt>e</tt> to this set if
* this set contains no element <tt>e2</tt> such that
* <tt>(e==null ? e2==null : e.equals(e2))</tt>.
* If this set already contains the element, the call leaves the set
* unchanged and returns <tt>false</tt>.
*
* @param e element to be added to this set
* @return <tt>true</tt> if this set did not already contain the specified
* element
*/
public boolean add(E e) {
return map.put(e, PRESENT)==null;
}
HashSet的add方法的底層說明:3~5行說明了add元素e的條件:set中不存在元素e2( e==null;e2==null;e.equals(e2) )。在元素都不為null的情況下罢低,說明這行代碼e.equals(e2) 與我們想要的結(jié)果不一樣.
public boolean equals(Object obj) {
return (this == obj);
}
看一下Object類中的equals方法查辩。發(fā)現(xiàn)代碼中原本想要覆蓋equals方法(發(fā)生覆蓋的條件:“三同一不低”,子類和父類的方法名稱网持,參數(shù)列表宜岛,返回類型必須完全相同,而且子類方法的訪問修飾符的權(quán)限不能比父類低功舀。)萍倡,可是卻重載了equals方法(發(fā)生重載的條件:方法名相同,參數(shù)列表(類型辟汰、個數(shù)列敲、順序)不同)。在進(jìn)行這行代碼( e.equals(e2) )時,就調(diào)用了Object類的equals方法,而Object類的equals方法是比較對象同一性的帖汞,即( e==e2 )戴而。例子中:這行代碼:bigrams.add(new Bigram(ch, ch)); 每次添加都會new Bigram(ch,ch),每一個Object都不一樣,自然循環(huán)多少次翩蘸,就add多少Object了所意。
隨著java 1.5發(fā)行版本中增加注解,類庫中也增加了幾種注解類型。其中Override只能用在方法聲明中扶踊,它表示被注解的方法聲明覆蓋了超類型中的一個聲明泄鹏。堅持使用這個注解,可以防止一大類非法錯誤秧耗。
@Override public boolean equals(Bigram bigram) {
return bigram.first == first && bigram.second == second;
}
如果插入這個注解备籽,重新編譯程序,編譯器會產(chǎn)生一條錯誤:
The method equals(Bigram) of type Bigram must override or implement a supertype method
針對提示的錯誤咱們就可以修改相應(yīng)的代碼分井,這個equals方法測試對象的同一性车猬,就像==:
@Override public boolean equals(Object o) {
if(!(o instanceof Bigram)) {
return false;
}
Bigram b = (Bigram) o;
return b.first == first && b.second == second;
}
總結(jié):如果在你想要的每個方法聲明中使用 Override 注解來覆蓋超類聲明 , 編譯器就可以替你防止大量錯誤 。在具體的類中 , 不必標(biāo)注你確信覆蓋了抽象方法聲明的方法(標(biāo)注也可以)杂抽。