java(11): Object 類學習 和 String 陷阱分析

1. 相等性的比較(==)

    a. 對於原生數據類型來說,比較的是左右兩邊的值是否相等。

    b. 對於引用類型來說,比較左右兩邊的引用是否指向同一個對象,或者說左右兩邊的引用地址是否相同。

2. Object 類是所有對象的父類 。

3. 

public class StringTest {
    public static void main(String[] args) {
        Object object = new Object();
        System.out.println(object);
        System.out.println(object.toString());
    }
}
// output
java.lang.Object@f5f2bb7
java.lang.Object@f5f2bb7

    當我們使用 System.out.println() 打印一個引用類型變量時,實際上會打印出引用所指向對象的 toString() 方法的返回值,因爲每個類都直接或間接地繼承自 Object,而 Object 類中定義了 toString(),因此每個類都有 toString() 方法。

public class StringTest {
    public static void main(String[] args) {
        String string = "ym";
        System.out.println(string);
    }
}
// output
ym

這是因爲 String 對象重寫了 Object 中的 toString() 方法,重寫之後就是返回這個對象的本身。

// JDK 中 Stirng 中 toString() 方法
/**
* This object (which is already a string!) is itself returned.
*
* @return  the string itself.
*/
public String toString() {
    return this;
}

再看看 Object 對象中的 toString() 源碼:

public String toString() {
    return getClass().getName() + "@" + Integer.toHexString(hashCode());
}

通過源碼我們就知道爲什麼上面返回的是 java.lang.Object@f5f2bb7。

4.

String 是常量,其一旦被創建便無法被改變。當使用 "+" 拼接時,就會創建新的對象,而不是往原有的對象拼接。

5.

下面看一段代碼,然後詳細分析一下:

public class StringTest {
    public static void main(String[] args) {
        Object object = new Object();
        Object object2 = new Object();
        System.out.println("1: " + (object == object2));

        String str = new String("ym");
        String str2 = new String("ym");
        System.out.println("2: " + (str == str2));

        String str3 = "ym";
        String str4 = "ym";
        System.out.println("3: " + (str3 == str4));

        String str5 = new String("ym");
        String str6 = "ym";
        System.out.println("4: " + (str5 == str6));

        String str7 = "ym";
        String str8 = "y";
        String str9 = "m";
        System.out.println("5: " + (str7 == str8 + str9));

        System.out.println("6: " + (str7 == "y" + "m"));
    }
}
// output
1: false
2: false
3: true
4: false
5: false
6: true

結果分析:

a. 1 和 2 都很容易,因爲它們指向的對象不同,所以其引用地址不一樣,結果自然就爲 false。

b. 3 的結果爲 true。這是因爲 Java 中有一個 String Pool (常量池)的概念,每次通過 string = "abc"(採用字面值方式賦值) 這種方式在代碼中創建 String 對象的時候會首先在 String Pool 中查找有沒有這個相同的對象,如果沒有就創建一個新的,如果有就不創建新的對象,直接將該對象的地址賦值給相應的引用類型變量。所以上面的 str3 創建了 "ym" 之後,str4 指向的也是同一個字符串對象,導致結果爲 true。

c. String s = new String("ym")創建過程:①首先在 String pool 中查找有沒有 "ym" 這個字符串對象,如果有,就不用在 String Pool 中再次創建這個對象了,直接在堆(heap)中創建一個 "ym" 字符串對象,然後將堆中這個對象的地址返回給引用變量 s,導致 s 指向堆中創建的這個字符串對象。②如果在 String Pool 中沒有,則先在 String Pool 中創建這個對象,然後再在堆中(heap)創建一個 "ym" 對象,最後將堆中的這個對象的地址賦值給引用變量 s,導致 s 指向堆中創建的這個字符串對象。所以在結果 4 中一個指向的是堆中的“ym”對象,一個指向的是棧中(stack)String Pool 中的“ym”對象,它們並不是同一個對象,所以結果返回 false。

d. str7 指向的是 String Pool 中的 "ym" 對象,而 str8 +str9 雖然內容也爲 "ym",但是這個 "ym" 對象是在堆中,所以 str8 +str9 是堆中 “ym”對象的內存地址,所以結果爲 false。

e. str7 指向的是 String Pool 中的 "ym" 對象,而 “y”+“m”創建的“ym”對象也是在 String Pool 中,而由於 String Pool 中已經存在了這個對象,所以它們指向的是同一個 String 對象。故爲true。

6. String 中的 intern() 方法

比如

String str ="ym".intern()

這個方法意思就是,目的是將 "ym" 對象的地址賦值給 str,而創建這個對象時,會首先在 String Pool 中找有沒有這個對象,如果有,就直接指向這個對象。如果沒有就在 String Pool 中創建這個對象之後再指向它。看個例子:

String str1 = "ym";
String str2 = new String("ym");
String str3 = str2.intern();
System.out.println(str1 == str3);  // true (因爲 str1 和 str3 都是指向 String pool 中的 "ym" 對象)
System.out.println(str2 == str3);  // false (因爲 str2 指向的是堆中的 "ym" 對象,而 str3 指向的是 String Pool 中的 "ym")

 

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