最近看了Object類(lèi)的源碼,對hashCode() 和equals()方法有了更深的認識。重寫(xiě)equals()方法就必須重寫(xiě)hashCode()方法的原因,從源頭Object類(lèi)講起就更好理解了。
先來(lái)看Object關(guān)于hashCode()和equals()的源碼:
public native int hashCode();- public boolean equals(Object obj) {
- return (this == obj);
- }
光從代碼中我們可以知道,hashCode()方法是一個(gè)本地native方法,返回的是對象引用中存儲的對象的內存地址,而equals方法是利用==來(lái)比較的也是對象的內存地址。從上邊我們可以看出,hashCode方法和equals方法是一致的。還有最關(guān)鍵的一點(diǎn),我們來(lái)看Object類(lèi)中關(guān)于hashCode()方法的注釋?zhuān)?p>- /**
- * Returns a hash code value for the object. This method is
- * supported for the benefit of hash tables such as those provided by
- * {@link java.util.HashMap}.
- * <p>
- * The general contract of {@code hashCode} is:
- * <ul>
- * <li>Whenever it is invoked on the same object more than once during
- * an execution of a Java application, the {@code hashCode} method
- * must consistently return the same integer, provided no information
- * used in {@code equals} comparisons on the object is modified.
- * This integer need not remain consistent from one execution of an
- * application to another execution of the same application.
- * <li>If two objects are equal according to the {@code equals(Object)}
- * method, then calling the {@code hashCode} method on each of
- * the two objects must produce the same integer result.
- * <li>It is <em>not</em> required that if two objects are unequal
- * according to the {@link java.lang.Object#equals(java.lang.Object)}
- * method, then calling the {@code hashCode} method on each of the
- * two objects must produce distinct integer results. However, the
- * programmer should be aware that producing distinct integer results
- * for unequal objects may improve the performance of hash tables.
- * </ul>
- * <p>
- * As much as is reasonably practical, the hashCode method defined by
- * class {@code Object} does return distinct integers for distinct
- * objects. (This is typically implemented by converting the internal
- * address of the object into an integer, but this implementation
- * technique is not required by the
- * Java? programming language.)
- *
- * @return a hash code value for this object.
- * @see java.lang.Object#equals(java.lang.Object)
- * @see java.lang.System#identityHashCode
- */
- public native int hashCode();
簡(jiǎn)單的翻譯一下就是,hashCode方法一般的規定是:- 1.在 Java 應用程序執行期間,在對同一對象多次調用 hashCode 方法時(shí),必須一致地返回相同的整數,前提是將對象進(jìn)行 equals 比較時(shí)所用的信息沒(méi)有被修改。從某一應用程序的一次執行到同一應用程序的另一次執行,該整數無(wú)需保持一致。
- 2.如果根據 equals(Object) 方法,兩個(gè)對象是相等的,那么對這兩個(gè)對象中的每個(gè)對象調用 hashCode 方法都必須生成相同的整數結果。
- 3.如果根據 equals(java.lang.Object) 方法,兩個(gè)對象不相等,那么對這兩個(gè)對象中的任一對象上調用 hashCode 方法不 要求一定生成不同的整數結果。但是,程序員應該意識到,為不相等的對象生成不同整數結果可以提高哈希表的性能。
再簡(jiǎn)單的翻譯一下第二三點(diǎn)就是:hashCode()和equals()保持一致,如果equals方法返回true,那么兩個(gè)對象的hasCode()返回值必須一樣。如果equals方法返回false,hashcode可以不一樣,但是這樣不利于哈希表的性能,一般我們也不要這樣做。重寫(xiě)equals()方法就必須重寫(xiě)hashCode()方法的原因也就顯而易見(jiàn)了。
假設兩個(gè)對象,重寫(xiě)了其equals方法,其相等條件是屬性相等,就返回true。如果不重寫(xiě)hashcode方法,其返回的依然是兩個(gè)對象的內存地址值,必然不相等。這就出現了equals方法相等,但是hashcode不相等的情況。這不符合hashcode的規則。下邊,會(huì )介紹在集合框架中,這種情況會(huì )導致的嚴重問(wèn)題。
- public class A {
- @Override
- public boolean equals(Object obj) {
- return true;
- }
- }
- public class B {
- @Override
- public int hashCode() {
- return 1;
- }
- }
- public class C {
- @Override
- public int hashCode() {
- return 2;
- }
- @Override
- public boolean equals(Object obj) {
- return true;
- }
- }
- public class HashSetTest {
- public static void main(String[] args) {
- HashSet hashSet = new HashSet();
- hashSet.add(new A());
- hashSet.add(new A());
- hashSet.add(new B());
- hashSet.add(new B());
- hashSet.add(new C());
- hashSet.add(new C());
- for (Object hs : hashSet) {
- System.out.println(hs);
- }
- //HashSet重寫(xiě)了toString()方法
- // System.out.println(hashSet);
- }
- }
其結果為:- cn.edu.uestc.collection.B@1
- cn.edu.uestc.collection.B@1
- cn.edu.uestc.collection.C@2
- cn.edu.uestc.collection.A@3f84246a
- cn.edu.uestc.collection.A@18a9fa9c
- Process finished with exit code 0
從上邊的程序結果可以看到,必須要同時(shí)重寫(xiě)這兩個(gè)方法,要不然Set的特性就被破壞了。- //f是Filed屬性
- boolean hashCode=(f?0:1)
- (byte,short,char,int) hashCode=(int)f
- long hashCode=(int)(f^(f>>>32))
- float hashCode=Float.floatToIntBits(f)
- double hashCode=(int)(1^(1>>>32))
- 普通引用類(lèi)型 hashCode=f.hashCode()
將計算出的每個(gè)Filed的hashCode值相加返回,為了避免直接相加產(chǎn)生的偶然相等(單個(gè)不相等,加起來(lái)就相等了),為每個(gè)Filed乘以一個(gè)質(zhì)數后再相加,例如有:return f1.hashCode()*17+(int)f2.13 - /**
- * Returns a hash code for this string. The hash code for a
- * <code>String</code> object is computed as
- * <blockquote><pre>
- * s[0]*31^(n-1) + s[1]*31^(n-2) + ... + s[n-1]
- * </pre></blockquote>
- * using <code>int</code> arithmetic, where <code>s[i]</code> is the
- * <i>i</i>th character of the string, <code>n</code> is the length of
- * the string, and <code>^</code> indicates exponentiation.
- * (The hash value of the empty string is zero.)
- *
- * @return a hash code value for this object.
- */
- public int hashCode() {
- int h = hash;
- if (h == 0 && value.length > 0) {
- char val[] = value;
- for (int i = 0; i < value.length; i++) {
- h = 31 * h + val[i];
- }
- hash = h;
- }
- return h;
- }
聯(lián)系客服