關於一段有趣代碼引出的String建立對象的解釋

一般來講,咱們認爲hashCode不相同就爲不一樣的對象。就這樣由一段代碼引起了一場討論,代碼以下:spa

 1     @Test
 2     public void stringCompare() {
 3         String s1 = "test";
 4         String s2 = "test";
 5         String s3 = new String("test");
 6         String s4 = new String("test");
 7 
 8         System.out.println("value compare:");
 9         System.out.println("s1.equals(s2):" + s1.equals(s2));
10         System.out.println("s2.equals(s3):" + s2.equals(s3));
11         System.out.println("s3.equals(s4):" + s3.equals(s4));
12         System.out.println("s1==s2:" + (s1 == s2));
13         System.out.println("s2==s3:" + (s2 == s3));
14         System.out.println("s3==s4:" + (s3 == s4));
15 
16         System.out.println("hashCode compare:");
17         System.out.println("s1~s2:"+ (s1.hashCode() == s2.hashCode()));
18         System.out.println("s2~s3:"+ (s2.hashCode() == s3.hashCode()));
19         System.out.println("s3~s4:"+ (s3.hashCode() == s4.hashCode()));
20     }


有興趣的話先猜一猜上面的打印結果。這段代碼能夠很好的說明String在建立對象的特殊性。
運行上面的代碼結果爲:code

    value compare:
    s1.equals(s2):true
    s2.equals(s3):true
    s3.equals(s4):true
    s1==s2:true
    s2==s3:false
    s3==s4:false
    hashCode compare:
    s1~s2:true
    s2~s3:true
    s3~s4:true


猜對了嗎?會不會有點奇怪,接下來我將逐一說明,並解釋String建立對象的機理。

首先咱們知道equals的比較是兩個對象的值是否相同,這個毋庸置疑,咱們都賦值「test」,因此結果必然是三個true,這一點沒有什麼問題。

而後看「==」的比較,「==」是比較物理地址時候相同,也是比較是否爲同一對象的手段。結果是s1和s2是true,後面的兩個比較是false,這就說明s1和s2指向的是同一塊地址。s3和s4是經過new出來的對象,咱們知道new一般是開闢了新空間,而直接賦值是引用賦值。因此這一點也基本上沒有什麼問題,這就解釋了s2==s3:false,s3==s4:false。

最後同一般咱們認爲hashCode不一樣就是不一樣的對象,可是這四個對象的hashCode是所有相同的。這彷佛和使用"=="比較有點違背。但其實並不矛盾,必須明確一點是hashCode和物理地址沒有必然的關係。之因此是這樣,是由於Sting在建立對象時的機制有所不一樣。

重點:
    JVM爲String類型提供了一個字符池(jdk7以前在permgen,jdk7以後也是堆裏)。每次在建立對象時,都會如今字符池中查找該字符串是否存在。這是大的前提邏輯,如今咱們就一下幾種狀況分別說明:對象

1.建立一個對象 String s1 = new String("我是字符串"),遵循大邏輯,先在pool中檢索,但其實不管pool中有沒有,都會建立一個新的對象。不一樣的是:
    a.pool中沒有:
        在pool中添加一個新的對象「我是字符串」,也就是說這裏建立了兩個對象,除了s1這個對象外,在pool中還建立了一個對象;這個時候建立s2 = "我是字符串"; 一樣檢查pool,發現已有,那s2指向pool中的「我是字符串」的地址。
    b.pool中有:
        則只建立一個對象及就是s1。這個時候建立s2= 「我是字符串」;一樣會檢查pool發現存在,那s2直接指向pool中的地址。
2.建立一個String s1 = "我是字符串",遵循大邏輯,先在pool中檢索:
    a.pool中沒有:
        在pool中沒有檢索到「我是字符串」,那麼在pool中添加一個字符串對象「我是字符串」,而後s1指向pool中的地址。這個時候若是建立String s2 = new String("我是字符串");檢測pool中已有,同1.b中建立s1過程。
    b.pool中有:
        在pool中檢索到,s1直接指向pool中的地址,若是建立String s2 = new String("我是字符串");同1.b中建立s1過程。blog

注意:字符串

  1.hashCode實際與物理地址沒有必然關係,只是習慣上咱們能夠用hashCode判斷是否爲同一對象。string

  2.pool也是有大小限制的,對於不用的字符串對象,垃圾機器人會回收,釋放空間。hash

相關文章
相關標籤/搜索