詳細解釋 hashcode equals() "==" 的區別和聯繫



最近 被  某某跟某某是否相等 給搞混了。。什麼物理地址  哈希值   對象的 引用 巴拉巴拉一大堆 。。
先上幾個結論  讓沒有時間的猿類 直接知道答案好了。:


結論就是:
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是比較內容的


Java中的集合(Collection)有兩類,
一類是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

後面留給觀衆 去思考了。。

我也是在網上各種百度各種嘗試 總結的。也找不到出處了。。總之是感謝 大神們的分享 。。




發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章