天天看點

【剪不斷,理還亂】Java 中 equals 和 == 的那些事細說 equals 和==的那些事

細說 equals 和==的那些事

1,起源于 Object

我們都知道 Java 中所有的類都預設繼承了 Object 這個超類,其中 Object 有 10 多個方法,這裡我們介紹一下主要的

toString

equals

hashcode

方法。

  • toSting

    方法預設傳回“

    類名@位址值

    ”;我們一般對它進行重寫,然後就可直接列印對象得到輸出重寫後的形式。

下面重點介紹一下

equals

hashcode

  • equals

    方法預設比較對象(位址),即進行的是==運算。如果需要比較内容,需要進行重寫。
  • hashcode

    預設是根據對象位址傳回一串整數,也就是說位址相同

    hashcode

    就相同。而且

    hashcode

    是 Object 中的

    native

    方法,本地方法,表明該方法事調用了别的語言實作的,有點像接口,不用自己實作。

下面是 Object 類中的相關源碼:

public String toString() {
        return getClass().getName() + "@" + Integer.toHexString(hashCode());
    }
           
public boolean equals(Object obj) {
        return (this == obj);
    }
           

2,糾纏在 String

我們再來說一下

java.lang.String

equals

hashcode

的特點:

String 對

equals

hashcode

都進行了重寫。

首先 hashcode 是根據對象内容計算 hash,是以對象内容相同,他們的 hashcode 就相同。

public int hashCode() {
        int h = hash;
        if (h == 0 && value.length > 0) {
            char val[] = value;
			
            //這種 hash 計算方式不難看出,元素 value 相同 h 會是一樣的
            for (int i = 0; i < value.length; i++) {
                h = 31 * h + val[i];
            }
            hash = h;
        }
        return h;
    }
           

對于 string 而言,equlas 比較的是對象内容,這也是由于字元串的特殊性。

那麼==比較的就是對象位址。

public boolean equals(Object anObject) {
    //對象相同,直接相同
        if (this == anObject) {
            return true;
        }
    //類型相同且每個元素值相同,認為相同
        if (anObject instanceof String) {
            String anotherString = (String)anObject;
            int n = value.length;
            if (n == anotherString.value.length) {
                char v1[] = value;
                char v2[] = anotherString.value;
                int i = 0;
                while (n-- != 0) {
                    if (v1[i] != v2[i])
                        return false;
                    i++;
                }
                return true;
            }
        }
        return false;
    }
           

3,代碼驗證

下面是測試代碼:

public class TEST {
    public static void main(String[] args){

        Object o1 = new Object();
        Object o2 = new Object();
        Object o3 = o2;
        System.out.println(o1==o2); //false
        System.out.println(o1.equals(o2)); //false,Object 原生 equals,預設比較位址
        System.out.println(o1.hashCode()==o2.hashCode()); //false,根據位址計算 hash
        System.out.println(o2.hashCode()==o3.hashCode()); //true

        String s1 = "abc";
        String s2 = s1; //常量池優化機制
        String s3 = new String("abc");
        System.out.println(s1==s3); //false 位址不一樣,一個在常量池中一個在堆中
        System.out.println(s1.equals(s3)); //true,比較内容
        System.out.println(s2.hashCode()==s1.hashCode()); //true,根據内容計算 hash
        System.out.println(s1.hashCode()==s3.hashCode()); //true
    }

}
           

4,重寫方法

有些場景中,我們需要自定義”相等“規則。比如我們定義對象的内容相同即為相等,此時需要重寫 equals 方法:

import java.util.Objects;

public class Person {	
	private String name;
	private int age;
	
    @Override
    public boolean equals(Object o) {
        // 如果對象位址一樣,則認為相同
        if (this == o)
            return true;
        // 如果參數為空,或者類型資訊不一樣,則認為不同
        if (o == null || getClass() != o.getClass())
            return false;
        // 轉換為目前類型
        Person person = (Person) o;
        // 要求基本類型相等,并且将引用類型交給 java.util.Objects 類的 equals 靜态方法取用結果
        return age == person.age && Objects.equals(name, person.name);
    }
}
           
//對象比較位址,字元串比較内容
 public static boolean equals(Object a, Object b) {
 //1,對象類型時
 //a==b 為 true,則 true
 //a==b 為 false,則 false;
 //2,string 類型時
 //位址 true,内容 true,則 true
 //位址 false,内容 true,則 true;位址不等内容不等,flase
        return (a == b) || (a != null && a.equals(b));
    }
           

在有些場合,我們還需要重寫 hashcode,比如 HashSet 中“元素相等”的判斷機制就是綜合考慮了 hashcode 和 equals 方法;是以當我們自定義對象時需要重寫 hashcode 和 equals 兩個方法。

equals 的方法重寫參考上例,下面是 hashcode 方法的重寫以及相應方法源碼:

@Override 
public int hashCode() {
     //仍然調用的是 Objects 的 hash 方法
    //對于這裡而言,age 走位址判斷;name 走内容判斷;是以隻要他們内容相同就會傳回相同的 hash
        return Objects.hash(name, age);
    }
           
public static int hash(Object... values) {
        return Arrays.hashCode(values);
    }
           
public static int hashCode(Object a[]) {
        if (a == null)
            return 0;

        int result = 1;
		//仍然走的是 Object 的 hashCode 方法
        for (Object element : a)
            result = 31 * result + (element == null ? 0 : element.hashCode());

        return result;
    }
           

當然上述重寫方法,idea 的 Generate 提供了重寫模闆,可一鍵生成。

5,總結

Object 的 hashcode 根據位址傳回值,equals 比較位址,==比較位址;

String 的 hashcode 根據内容傳回值,equals 比較内容,==比較位址。

即 Object 一律比較的是位址,由于 String 進行了方法重寫,都是比較的内容。==其實本身就是比較位址。