equals()和==的比較

轉載   http://blog.csdn.net/u013054285/article/details/78985798

1.equals()和==是什麼?

equals():是方法,定義在超類Object中的一個方法,用來比較兩個對象。 
==:是操作符,用來比較兩個對象。

爲什麼會將一個操作符和一個方法進行比較呢? 
因爲它們都是用來比較兩個對象的,但它們在用法上又有些區別。 
這些區別如果不稍加註意,在開發的過程中就很容易翻車。

個人理解:
==和equals()作用是相同的。
但是equals()是一個方法,可以重寫equals()方法,實現不同的作用。比如String類中的eqauls()方法。

2.爲什麼說它們是一樣的?

我們來看一下Object中是如何實現eqauls()方法,代碼如下:

public boolean equals(Object obj) {
    return (this == obj);
}

很明顯,在源代碼中,equals()方法返回的就是使用 == 比較兩個對象後的結果。 
從這個角度來說,我認爲它們的作用是一樣的,都是用來比較兩個對象的引用的。

3.它們的區別在哪?

最直觀的來看,==是操作符,eqauls()是超類Object中的方法,這是最基本的區別。 
正是由於這個區別,纔有了== 和eqauls()的不同用法。 
首先,eqauls()方法是超類Object中的方法,而Java中所有的對象都是繼承自Object類的,所以子類是可以重寫eqauls()方法而實現不同的功能。 
最典型的就是String類中的equals()方法,代碼如下:

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;
}通過代碼我們發現,String重寫了equals()方法,從引用地址比較變成引用內容的比較。

4.栗子

4.1.第一個栗子:

我們先來比較下基本數據類型:

public static void main(String[] args) {
    int a = 3;
    int b = 3;
    System.out.println(a == b);
}
console:
true

對8種基本數據類型使用==比較。

Tips:首先基本數據類型不是對象,也就不是Object類的子類了,所以沒有equals()方法。 
但是這好像又違反了Java的“一切都是對象”的準則,所以,Java就給基本數據類型提供了包裝類型。

4.2.第二個栗子:

我們來比較下String類型:

public static void main(String[] args) {
    String str1 = "abc";
    String str2 = new String("abc");
    System.out.println(str1 == str2);
    System.out.println(str1.equals(str2));

    String str3 = "abc";
    System.out.println(str1 == str3);
    System.out.println(str1.equals(str3));
}
console:
false
true
true
true

String類型爲什麼會產生這種結果呢? 
首先我們來了解String的兩種創建方式:

  • 使用引號創建:創建的對象會存放在字符串緩衝池中。當創建str1時,JVM會在字符串緩衝池中尋找”abc”,沒有找到,則創建”abc”,然後將str1指向”abc”。創建str2的過程和創建str1是一樣的,只不過此時字符串緩衝池中包含了”abc”,則直接將str2指向”abc”。
  • 使用new創建:使用new來創建對象,存放在堆中,而且每次都會重新創建一個對象。

再結合我們對 == 和equals()的分析,以及String類對equals()的重寫,我們很容易就會明白爲什麼會是這種結果了。

Tips: String類提供了一個intern()的方法。如果對str2使用intern()方法,代碼如下:

public static void main(String[] args) {
    String str1 = "abc";
    String str2 = new String("abc");
    str2 = str2.intern();
    System.out.println(str1 == str2);
    System.out.println(str1.equals(str2));
}
console:
true
true

爲什麼會產生這種結果呢?我們來看下官方是怎麼說的。 
在String類的源碼中,我們找到intern()方法,官方提供了一段註釋,其中有一段是這麼寫的

/* When the intern method is invoked, if the pool already contains a
* string equal to this {@code String} object as determined by
* the {@link #equals(Object)} method, then the string from the pool is
* returned. Otherwise, this {@code String} object is added to the
* pool and a reference to this {@code String} object is returned.
*/

大概意思就是說:調用intern()方法的時候,會首先查找緩衝池中是否有這個字符串,如果有,直接返回;如果沒有,則在緩衝池中創建這個字符串,然後返回對象的引用。

4.3.第三個栗子:

我們首先定義一個Cat類

public class Cat {
}

然後我們在方法中進行比較:

public static void main(String[] args) {
    Cat cat1 = new Cat();
    Cat cat2 = new Cat();
    System.out.println(cat1 == cat2);
    System.out.println(cat1.equals(cat2));

    Cat cat3 = cat1;
    System.out.println(cat1 == cat3);
    System.out.println(cat1.equals(cat3));
}
console:
false
false
true
true

首先我們創建了cat1對象,並在堆中爲其分配了一塊地址,而cat1存儲的是指向這塊地址的引用。 
然後我們創建了cat2對象,和cat1一樣,在堆中分配了一塊地址,然後cat2存儲了指向這塊地址的引用。 
這樣,我們在堆中有了兩個Cat類的實例對象。而根據==和equals()的規則,cat1和cat2的比較自然不相同。 
在創建cat3的時候,我們直接將cat1賦值給了cat3,則cat3中也是存儲了和cat1一樣的地址。

5.什麼時候用?

==:通常我們用在基礎數據類型的比較上,因爲基礎類型的特殊性,所以可以直接使用==來比較基礎數據類型的值。同時我們也可以用來比較兩個對象是不是同一個對象。 
equasl():我們通常用來比較兩個對象,或者用來比較String對象的內容。更重要的是,如果有特殊的業務需求,我們可以重寫equasl()方法,來實現我們的目的。

6.結語

在equals()和==的比較中,其實涉及到很多JVM內存的知識。關於內存的問題,我會在後期專門寫出來和大家分享的。 
關於equals()和==的比較,我已經簡單的說完了,但是由於個人水平有限,其中難免會出現不夠嚴謹和錯誤的地方,希望大家不吝賜教。

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