equals()是判讀兩個Set是否相等[前提是equals()在類中被覆蓋]。==決定引用值是否指向同一對象。
1、當向集合set中增加對象時,首先計算要增加對象的hashCode碼,根據該值來得到一個位置來存放當前的對象,當在該位置沒有一個對象存在的話,那么集合set認為該對象在集合中不存在,直接增加進去。如果在該位置有一個對象的話,接著將準備增加到集合中的對象與該位置上的對象進行equals方法比較,如果該equals方法返回false,那么集合認為集合中不存在該對象,再進行一次散列,將該對象放到散列后計算出的新地址里,如果equals方法返回true,那么集合認為集合中已經存在該對象了,不會再將該對象增加到集合中了。
2、當重寫equals方法時,必須要重寫hashCode方法。在java的集合中,判斷兩個對象是否相等的規則是:
1),判斷兩個對象的hashCode是否相等
如果不相等,認為兩個對象也不相等,完畢 ; 如果相等,轉入2
2),判斷兩個對象用equals運算是否相等
如果不相等,認為兩個對象也不相等
如果相等,認為兩個對象相等(equals()是判斷兩個對象是否相等的關鍵)
可見hashcode()相等時,equals()方法也可能不等。
public static void main(String args[]){
String s1=new String("zhaoxudong"); //此語句創建了兩個對象,一個是字符串對象“zhaoxudong”(存放于棧中的字面量),另一個是new后在堆中產生的對象。詳細見下面的四.4
String s2=new String("zhaoxudong");
//上述兩條語句一共是產生了三個對象,因為棧中只有產生了一個對象。
System.out.println(s1==s2);//false
System.out.println(s1.equals(s2));//true
System.out.println(s1.hashCode());//s1.hashcode()等于s2.hashcode() ,指向同一內存的引用
System.out.println(s2.hashCode()); //equals和hashCode方法只用于兩個對象的比較和容器中,與對象的創建沒有關系
Set hashset=new HashSet();
hashset.add(s1);
hashset.add(s2); /*在添加s1,s2時, hashset認為s1和s2是相等的,所以讓s2覆蓋了s1;*/
Iterator it=hashset.iterator();
while(it.hasNext()){
System.out.println(it.next());
} //最后在while循環的時候只打印出了一個”zhaoxudong”。
這是因為String類已經重寫了equals()方法和hashcode()方法。
但是看下面的程序:
public class HashSetTest {
public static void main(String[] args) {
HashSet hs=new HashSet();
hs.add(new Student(1,"zhangsan"));
hs.add(new Student(2,"lisi"));
hs.add(new Student(3,"wangwu"));
hs.add(new Student(1,"zhangsan"));
Iterator it=hs.iterator();
while(it.hasNext()){
System.out.println(it.next());
} } }
class Student {
int num;
String name;
Student(int num,String name) {
this.num=num;
this.name=name; }
public String toString() { return num+":"+name; }
}
輸出結果為:
1:zhangsan
1:zhangsan
3:wangwu
2:lisi
問題出現了,為什么hashset添加了相等的元素呢,這是不是和hashset的原則違背了呢?回答是:沒有因為在根據hashcode()對兩次建立的new Student(1,"zhangsan")對象進行比較時,生成的是不同的哈希碼值,所以hashset把他當作不同的對象對待了,當然此時的equals()方法返回的值也不等。那么為什么會生成不同的哈希碼值呢?原因就在于我們自己寫的Student類并沒有重新自己的hashcode()和equals()方法,所以在比較時,是繼承的object類中的hashcode()方法,它是一個本地方法,比較的是對象的地址(引用地址),使用new方法創建對象,兩次生成的當然是不同的對象了,造成的結果就是兩個對象的hashcode()返回的值不一樣。那么怎么解決這個問題呢??
答案是:在Student類中重新hashcode()和equals()方法。
例如:
class Student{
int num;
String name;
Student(int num,String name){
this.num=num;
this.name=name; }
public int hashCode(){ //重寫hashCode的方法
return num*name.hashCode(); }
public boolean equals(Object o) {
Student s=(Student)o;
return num==s.num && name.equals(s.name); //&&的優先級比==低,所以前面不必加括號
}
public String toString(){return num+":"+name; }
}
根據重寫的方法,即便兩次調用了new Student(1,"zhangsan"),我們在獲得對象的哈希碼時,根據重寫的方法hashcode(),獲得的哈希碼肯定是一樣的。所以運行修改后的程序時,我們會看到重復元素的問題已經消除。
在hibernate的pojo類中,經常使用set集合來保存相關對象,而set集合是不允許重復的。所以需要重寫equals和hashCode()方法。
比如可以這樣寫:
public int hashCode(){
return 1;}//等價于hashcode無效
這樣做的效果就是在比較哈希碼的時候不能進行判斷,因為每個對象返回的哈希碼都是1,每次都必須要經過比較equals()方法后才能進行判斷是否重復,這當然會引起效率的大大降低。
本文來自CSDN博客,轉載請標明出處:http://blog.csdn.net/elia1208/archive/2009/10/12/4657644.aspx