天天看點

Java中的 == 和 equals 差別

Java中的 == 和 equals 到底有什麼差別?

  1. 提到Java的 == 和 equals,很多人就會說 == 比較的值(位址), equals比較内容,這句話到底對不對?

    equals是object類的一個方法,定義如下:

    public boolean equals(Object obj) {

    return (this == obj);

    }

    我們看到,當調用equals時, 實際還是調用了 == ,而 == 操作符 當且僅當 左右兩端的值相等時傳回true,那麼我們常說的equals比較内容又有錯嗎?錯在哪裡?

    實際上我們口中說的比較内容大都是說String類,String類重寫了Object的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方法同樣先 == 判斷,如果值相等傳回true,否則将比較對象轉成String(此處講解String比較),而後比較它們的字元序列,這就是常說的“内容”, equals方法相對簡單,不做過多講解。

    2. 為什麼Java中字元串比較都用equals而不用 ==

    上面已經講到字元串的equals方法,幾個字元串 == 比較的示例代碼,讀者可以不看答案自己心裡先思考一下是否相等,看看自己是否了解了 字元串的 == 操作。

    public static final String str0 = “abcde”;

    public static void main(String[] args) {

    String strObj = new String(“abc”);

    String strObj1 = new String(“abc”);

    String strObj2 = new String(“de”);

    String str1 = “abc”;

    String str2 = “de”;

    final String str3 = “abc”;

    final String str4 = “de”;

    System.out.println(strObj == strObj1);//false

    System.out.println(strObj.intern() == strObj1.intern()); //true

    System.out.println((strObj1 + strObj2) == str0); //false

    System.out.println((str1 + str2) == str0);//false

    System.out.println((str1 + str2).intern() == str0);//true

    System.out.println((str3 + str4) == str0);//true

    System.out.println((str3 + str4).intern() == str0); //true

    首先 new String 操作會在堆上建立一個String對象,若字元串常量池中沒有此字元串則也會在常量池中放一份,這裡也有一道面試題String a = “a”;和String a = new String(“a”)有什麼差別,差別就是前者建立一個後者則會建立兩個, 是以這裡第一個就會傳回false。

    Java中的 == 和 equals 差別

    String.intern方法,如果常量池中已有此對象則傳回該對象的引用, 如果沒有則在常量池中放一份并傳回該引用。是以,strObj.intern()時常量池沒有,會放入“abc”,并傳回該引用,而strObj1.intern()時常量池中已有該字元串,則直接傳回該引用,是以位址值相等,傳回true。

    第三行,被 String類對+操作符的重載導緻字元串相加實際上是建立了StringBuilder對象的append方法之後調用ToString()實作的,是以等同于:

    new StringBuilder().append(strObj1).append(strObj2).toString(),顯然是false。

    第四行,和第三行一樣,傳回false。

    第五行,有了前面的基礎,第五行可以看作是"abcde".intern() == “abcde”,這樣傳回true就不難了解了,因為字元串”abcde“已經存在,直接傳回引用。

    第六行,這裡注意,與前面的差別是final修飾符,被final修飾的不可變量會在編譯期優化掉,是以第六行編譯期間就會"知道" str3 + str4實際上是"abcde"。

    第七行在第六行的基礎上已經是顯而易見了。

    實際上,字元串字面量相加也會被編譯優化,例如 String test = “abc” + “de”;也會在編譯期被認為String test = “abcde”;是以,如果聲明了這個test,則test == str0和 (“abc” + “de”)== str0都會傳回true。