(2011-12-27 20:40:27)java
轉載▼spa
標籤: it |
最近在論壇上看到關於String s = new String("XYZ") + new String("XYZ");到底建立幾個對象的討論,以爲比較有意思,在此總結一下。 .net
在JAVA中除了8種基本類型以外,其餘的都是類對象及其引用。因此 "XYZ"在JAVA中是一個String對象,對於String類對象來講它的對象值是不能修改的,也就是具備不變性。orm
可是在下面一段程序中:對象
view plainprint?blog
public class TestString { 內存
public static void main(String args[]) { ci
String s = "Hello"; 字符串
s = "Java"; get
String s1 = "Java";
String s2 = new String("Java");
System.out.println(s);
System.out.println(s == s1);
System.out.println(s == s2);
}
}
打印出s的結果是"Java",看起來s所引用的String變量好像是被修改了,可是若是你瞭解JVM(Java虛擬機)處理String變量時的機制,你就會知道事實並不是如此。
在JVM的工做過程當中,會建立一片的內存空間專門存入String對象,咱們把這片內存空間叫作String池。
對於語句String s= "Hello";,當JVM看到"Hello"時,會在String池建立String對象存儲它,並將它的引用返回給String變量s。
語句s = "Java";,當JVM看到"Java"時,會在String池建立新的String對象存儲它,再把新建的String對象的引用返回給String變量s。而原先的String對象"Hello"仍然在String池內,並無消失,它是不能被修改的。
因此咱們僅僅是改變了變量s的引用,而沒有改變它所引用的對象,由於String對象的值是不能被修改的。
String s1 = "Java";,JVM首先在String池裏面看可否找到字符串"Java",若是找到則返回它的引用給s1,不然建立新的String對象,放到String池裏。這裏因爲有s = "Java",因此對象已經被引用,因此依據規則s和s1都是引用同一個對象。因此s==s1返回true。(注: 比較運算符==,對於非基本類型,是比較兩引用是否引用內存中的同一個對象)。
String s2 = new String( "Java");,JVM首先仍是在String池裏面看可否找到字符串 "Java",若是找到,不作任何事情;不然建立新的String對象,放到String池裏面。因爲遇到了new關鍵字,還會在內存上(不是String池裏面)建立String對象存儲 "Java",並將內存上的(不是String池裏面的)String對象返回給s2。因此s==s2將返回false,由於它們引用的不是同一個對象。
因此對於語句String s = new String("XYZ") + new String("XYZ");
JVM先在String池中建立一個String對象存儲"XYZ",而後因爲遇到new關鍵字,再在內存上建立一個String對象存儲"XYZ";
接着因爲String池中已經有了"XYZ"的對象,因此第二個new語句不會在String池中建立對象,而只會在內存上建立一個String對象;
最後兩個字符串相加會在String池中建立一個String對象"XYZXYZ",並將其引用傳給s。
因此總共會建立4個String對象。
注意:「最後兩個字符串相加會在String池中建立一個String對象"XYZXYZ",並將其引用傳給s。」最後這句話可能有問題!
public static void main(String[] args) {
String xyzxyzOne = "xyzxyz";
String xyzOne = new String("xyz");
String xyzTwo = new String("xyz");
String xyzxyzTwo = xyzOne + xyzTwo;
System.out.println("(xyzxyzOne == xyzxyzTwo):"
+ (xyzxyzOne == xyzxyzTwo));
}
輸出爲:(xyzxyzOne == xyzxyzTwo):false
因此應該是在內存中建立的String對象。