最近 被 某某跟某某是否相等 給搞混了。。什麼物理地址 哈希值 對象的 引用 巴拉巴拉一大堆 。。
先上幾個結論 讓沒有時間的猿類 直接知道答案好了。:
結論就是:
1。如果兩個對象相同(a.equlas(b)),那麼它們的hashCode值一定要相同;
2。如果兩個對象的hashCode相同,它們並不一定相同 (有何能a.equals(b)爲false)
關於(==)
如果是 單純的數據類型的比較 就只是比較值是否相同
如果是類對象 對象引用的比較就是 比較 他們在內存中的地址 值是否相同。。
hashcode()的默認值是內存地址 == 符號兩端 盡享判斷的 也是內存地址 。。只是 如果hashcode被重寫了。就不一定是內存地址了。
(1)如果是基本類型比較,那麼只能用:==來比較,不能用equals
(2)對於基本類型的包裝類型,比如Boolean、Character、Byte、Shot、Integer、Long、Float、Double等的引用變量,==是比較地址的,而equals是比較內容的
一類是List ---集合內的元素是有序的,元素可以重複
一類是Set ---元素無序,但元素不可重複
那麼問題來了:怎麼判斷他們不重複呢? 總用equlas()太麻煩了。。如果有100000個數據,添加第100001個。就要判斷100000次。那估計的死了,所以hashcode就來了。
hashcode
是object的方法 他默認的就是 內存地址 所有事物都繼承了Object所以都有 hashcode方法。 就是爲了存數據更快一些。。
怎麼快得呢?
java存東西 先看 hashcode 如果這個相同 再判斷 equals() 如果再在相同就 代表兩個 是一個東西 就不存了因爲內存裏面已經有了 沒必要再存了
如果equals()不同 那麼就保存 ,具體保存到哪呢(網上說什麼的都有,反正他們返回的hashcode()是一樣的)。
這樣就大大降低了 效率 面的每個都去查找
equals
也是 object的方法 。
public boolean equals(Object obj) {
return (this == obj);
}
也是使用了 (==) 這個符號。。就是看這兩個的地址是否相同。。這是 Object類中的方法
但是其他方法都會 重寫object方法。所以呢 equlas()就是判斷 內存中這兩個 類 或者是內容 是否相同。。
equals 方法在非空對象引用上實現相等關係: (感覺面試會用到。)
自反性:對於任何非空引用值 x,x.equals(x) 都應返回 true。
對稱性:對於任何非空引用值 x 和 y,當且僅當 y.equals(x) 返回 true 時,x.equals(y) 才應返回 true。
傳遞性:對於任何非空引用值 x、y 和 z,如果 x.equals(y) 返回 true,並且 y.equals(z) 返回 true,那麼 x.equals(z) 應返回 true。
一致性:對於任何非空引用值 x 和 y,多次調用 x.equals(y) 始終返回 true 或始終返回 false,前提是對象上 equals 比較中所用的信息沒有被修改。
對於任何非空引用值 x,x.equals(null) 都應返回 false。
下面是代碼:
public static void main(String args[]){
String s1=new String("zhaoxudong");
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());
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”。 輸出結果爲:false
true
-967303459
-967303459
這是因爲String類已經重寫了equals()方法和hashcode()方法,
所以在根據上面的第1.2條原則判定時,hashset認爲它們是相等的對象,進行了重複添加。
import java.util.*;
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()方法返回的值也不等(這個不用解釋了吧)。那麼爲什麼會生成不同的哈希碼值呢?上面我們在比較s1和s2的時候不是生成了同樣的哈希碼嗎?原因就在於我們自己寫的Student類並沒有重新自己的hashcode()和equals()方法,所以在比較時,是繼承的object類中的hashcode()方法,它是一個本地方法,比較的是對象的地址(引用地址),使用new方法創建對象,兩次生成的當然是不同的對象了(這個大家都能理解吧。。。),造成的結果就是兩個對象的hashcode()返回的值不一樣。所以根據第一個準則,hashset會把它們當作不同的對象對待,自然也用不着第二個準則進行判定了。那麼怎麼解決這個問題呢??
答案是:在Student類中重新hashcode()和equals()方法。/
class Student {
int num;
String name;
Student(int num,String name)
{this.num=num;
this.name=name;
}
public int 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(),
獲得的哈希碼肯定是一樣的(這一點應該沒有疑問吧)。
當然根據equals()方法我們也可判斷是相同的。
所以在向hashset集合中添加時把它們當作重複元素看待了。
所以運行修改後的程序時,我們會發現運行結果是:
1:zhangsan
3:wangwu
2:lisi
可以看到重複元素的問題已經消除
下面是equlas()和 == 的關係
String s1 = "123";
String s2 = "123";
String s3 = "abc";
String s4 = new String("123");
String s5 = new String("123");
String s6 = new String("abc");
System.out.println(s1 == s2);// (1)true
System.out.println(s1.equals(s2));// (2)true
System.out.println(s1 == s3);// (3)flase
System.out.println(s1.equals(s3));// (4)flase
System.out.println(s4 == s5);// (5)flase
System.out.println(s4.equals(s5));// (6)true
System.out.println(s4 == s6);// (7)flase
System.out.println(s4.equals(s6));// (8)flase
System.out.println(s1 == s4);// (9)false
System.out.println(s1.equals(s4));// (10)true
String s2 = "123";
這一句會把數據放到一個常量池中,,這個裏面的數據也都不一樣 如果一樣 所以 兩個引用s1和s2 都指向“123” 所以他們的引用地址 是一樣的。。所以是true
後面留給觀衆 去思考了。。
我也是在網上各種百度各種嘗試 總結的。也找不到出處了。。總之是感謝 大神們的分享 。。