一般來講,咱們認爲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