1. 程式人生 > >小白過來看!!!java的==和equals()方法一樣嘛?equals()和hashCode()到底有何聯絡?

小白過來看!!!java的==和equals()方法一樣嘛?equals()和hashCode()到底有何聯絡?

很多人都知道物件a,物件b     a==b比較的是兩者之間的記憶體地址,a.equals(b)=true 比較的是a與b的字串內容。

但其實單單隻知道這些只能說是初學者必須知道的東西,下面根據我淺薄的知識來給小白們擴充擴充,當然,歡迎大佬們來補充,我還有很多需要學習的地方,若有不對的地方,請各位幫忙指出,謝謝大家!!

具體的說,對於基本型別來說==比較的是兩者的值,對於物件型別==比較的是記憶體地址。

         int a=1;
        int b=1;
        Integer c=new Integer(2);
        Integer d=new Integer(2);
        System.out.println(a==b);//返回true

        System.out.println(c==d);//返回false

equals():

為了更好的引申出equals方法,在這裡我定義了一個類部類User,通過new出兩個例項來比較

java的equals()方法,我們可以從原始碼得知equals()存在Object類,因為Object類是所有類的直接或間接的父類,所以我們可以知道equals()繼承自Object類,通過原始碼我們可以看出,equals()的底層方法依賴的是==(可以參考下圖1),也就是equals()原始方法與==是相同的,都是比較的記憶體地址,但是java提供的類中,大多都重寫了equals(),使equals()比較的是兩者物件的值。

                                圖1

下面為了驗證equals方法有被重寫,我重寫了equals()方法

輸出結果:

由此也就真相大白了。

那麼equals和hashCode有何關係?

想知道兩者之間的關係,我們先了解一下hashCode是什麼,這裡我從網上找了更權威的相關解釋

hashCode() 的作用是獲取雜湊碼,也稱為雜湊碼;它實際上是返回一個int整數。這個雜湊碼的作用是確定該物件在雜湊表中的索引位置。

從原始碼可以看到,hashCode源自Object類中,也就是java中所有類都有hashCode方法。 雖然,每個Java類都包含hashCode() 函式。但是,僅僅當建立並某個“類的散列表”(關於“散列表”見下面說明)時,該類的hashCode() 才有用(作用是:確定該類的每一個物件在散列表中的位置;其它情況下(例如,建立類的單個物件,或者建立類的物件陣列等等),類的hashCode() 沒有作用。
       上面的散列表,指的是:Java集合中本質是散列表的類,如HashMap,Hashtable,HashSet。

       也就是說:hashCode() 在散列表中才有用,在其它情況下沒用。在散列表中hashCode() 的作用是獲取物件的雜湊碼,進而確定該物件在散列表中的位置。

那麼雜湊碼是什麼?

不必用冗長的線性搜尋技術來查詢一個鍵,而是用一個特殊的值,名為“雜湊碼”。雜湊碼可以獲取物件中的資訊,然後將其轉換成那個物件“相對唯一”的整數(int)。所有物件都有一個雜湊碼,而hashCode()是根類Object的一個方法...

  實際的使用中,一個物件一般有key和value,可以根據key來計算它的hashCode。假設現在全部的物件都已經根據自己的hashCode值儲存在不同的儲存區域中了,那麼現在查詢某個物件(根據物件的key來查詢),不需要遍歷整個集合了,現在只需要計算要查詢物件的key的hashCode,然後找到該hashCode對應的儲存區域,在該儲存區域中來查詢就可以了,這樣效率也就提升了很多。說了這麼多相信你對hashCode的作用有了一定的瞭解,下面就來看看hashCode和equals的區別和聯絡。

Java對於eqauls方法和hashCode方法是這樣規定的:
1 如果兩個物件相同,那麼它們的hashCode值一定要相同。也告訴我們重寫equals方法,一定要重寫hashCode方法,也就是說hashCode值要和類中的成員變數掛上鉤,物件相同–>成員變數相同—->hashCode值一定相同。
2 如果兩個物件的hashCode相同,它們並不一定相同,這裡的物件相同指的是用eqauls方法比較。

對於需要大量並且快速的對比的話如果都用equal()去做顯然效率太低,所以解決方式是,每當需要對比的時候,首先用hashCode()去對比,如果hashCode()不一樣,則表示這兩個物件肯定不相等(也就是不必再用equal()去再對比了),如果hashCode()相同,此時再對比他們的equal(),如果equal()也相同,則表示這兩個物件是真的相同了,這樣既能大大提高了效率也保證了對比的絕對正確性!

這種大量的並且快速的物件對比一般使用的hash容器中,比如hashset,hashmap,hashtable等等,比如hashset裡要求物件不能重複,則他內部必然要對新增進去的每個物件進行對比,而他的對比規則就是像上面說的那樣,先hashCode(),如果hashCode()相同,再用equal()驗證,如果hashCode()都不同,則肯定不同,這樣對比的效率就很高了。

        Person p1 = new Person(18);
        Person p2 = new Person(18);
        System.out.println(p1.equals(p2));//true

p1.equals(p2)返回true,是因為equals()被重寫,而hashcode()沒有被重寫,p1.hashCode()==865113938,p2.hashCode()==1442407170,因此兩者的hashCode不相同,違背了hibernate的原則 由此hibernate會產生錯誤判斷,又以為它們不是同一個物件,因此我們還得重寫hashCode方法。如何重寫hashCode方法呢?

雜湊碼(HashCode)

雜湊碼產生的依據:雜湊碼並不是完全唯一的,它是一種演算法,讓同一個類的物件按照自己不同的特徵儘量的有不同的雜湊碼,但不表示不同的物件雜湊碼完全不同。也有相同的情況,看程式設計師如何寫雜湊碼的演算法。

雜湊碼要完成這麼一件事,首先要保證如果equlas出來的結果相等,那麼hashCode也相等。像上面的u1和u2,由於名字都是“張三”,所以應該返回相同的hashCode。所以我們可以想一個辦法。讓Person的雜湊碼返回Person裡面age欄位的雜湊碼,這樣就保證,年齡相同的人,不但equlas方法相同,而且hashCode相等。

重寫之後:

class Person{
	private String age;

	public Person(String age) {
		this.age = age;
	}

	public String getAge() {
		return age;
	}

	public void setAge(String age) {
		this.age = age;
	}


	@Override
	public boolean equals(Object obj) {
		if(!(obj instanceof Person)) {
			return false;
		}
		Person p = (Person) obj;
		if(this.age==p.age) {
			return true;
		}else {
			return false;
		}
	}

	@Override
	public int hashCode() {
		return age.hashCode();
	}
	

這樣可以保證hibernate根據我們自己的需求來判斷重複物件。

Hibernate是一個開放原始碼的物件關係對映框架,它對JDBC進行了非常輕量級的物件封裝,它將POJO與資料庫表建立對映關係,是一個全自動的orm框架,hibernate可以自動生成SQL語句,自動執行,使得Java程式設計師可以隨心所欲的使用物件程式設計思維來操縱資料庫。 Hibernate可以應用在任何使用JDBC的場合,既可以在Java的客戶端程式使用,也可以在Servlet/JSP的Web應用中使用,最具革命意義的是,Hibernate可以在應用EJB的J2EE架構中取代CMP,完成資料持久化的重任。

                Person p1 = new Person("17");
		Person p2 = new Person("18");
		System.out.println(p1.equals(p2));
		System.out.println(p1.hashCode());
		System.out.println(p2.hashCode());

結果:

false
1574
1575