-
s = new String("xyz");建立了幾個String Object?兩個對象,一個是「xyx」,一個是指向「xyx」的引用對象s。
String s="你好";int i=3; s=i+s; 這個表達式對嗎?在java中會提示資料型別不符。因為string是類別!正確做法: s+="3" 或s+='3'或s+=(char)i;
我們要引入另外一種創建String物件的方式的討論——引號內包含文字。這種方式是String特有的,它與new的方式有很大差異。
在JAVA虛擬機(JVM)中存在著一個字串池,其中保存著很多String對象,並且可以被共享使用,因此它提高了效率。 String a="abc";,這行程式碼被執行的時候,JAVA虛擬機首先在字串池中查找是否已經存在了值為"abc"的這麼一個對象,判斷依據是String類equals(Object obj)方法的回傳值。如果有,則不再創建新的對象,直接返回已存在對象的引用;如果沒有,則先創建這個對象,然後把它加入到字符串池中,再將它的引用返回。
字串物件的建立:由於字串物件的大量使用[它是一個對象,一般而言物件總是在heap分配記憶體],Java中為了節省記憶體空間和運行時間[如比較字串時,==比equals()快],在編譯階段就把所有的字串文字放到一個文字池中,而執行時間文字池成為常數池的一部分。文字池的好處,就是該池中所有相同的字串常數被合併,只佔用一個空間。我們知道,對兩個引用變量,使用==判斷它們的值[引用]是否相等,即指向同一個物件:
現在看String s = new String("abc");語句,這裡"abc"本身就是pool中的一個對象,而在執行時執行new String()時,將pool中的物件複製一份放到heap中,並且把heap中的這個物件的引用交給s持有。 ok,這條語句就建立了2個String物件。
String s1 = new String("abc") ;String s2 = new String("abc") ;if( s1 == s2 ){ //不會執行的語句}
//建立了幾個String Object? [三個,pool中一個,heap中2個。 ]
只有使用引號包含文字的方式建立的String物件之間使用「+」連接產生的新物件才會被加入字串池中。對於所有包含new方式新建物件(包括null)的「+」連線表達式,它所產生的新物件都不會被加入字串池中。
1.==表示引用自同一對象,equals()表示值相等。
String str1 = "abc";引用的物件在堆疊(或叫String池)中。
String str1 =new String ("abc"); 引用的物件在記憶體/堆中。
2.String str1 = "string";在堆疊中
String str3 = "str";在堆疊中
String str4 = "ing";在堆疊中
String str2 = str3+str4; 在堆疊中,因為+號的作用是傳回另一個新建的String對象,而不是在堆疊中找string這個值。如果是String str2 = "str"+"ing";那最後的結果就在堆疊中。 str1==str2為true。
但是有一種情況需要引起我們的注意。請看下面的程式碼:
public class StringStaticTest {
public static final String A = "ab"; // 常數A
public static final String B = "cd"; // 常數B
public static void main(String[] args) {
String s = A + B; // 將兩個常數用+連接對s進行初始化
String t = "abcd";
if (s == t) {
System.out.println("s等於t,它們是同一個物件");
} else {
System.out.println("s不等於t,它們不是同一個物件");
}
}
}
這段程式碼的運行結果如下:
s等於t,它們是同一個對象
原因是在上面的例子中,A和B都是常數,值是固定的,因此s的值也是固定的,它在類別被編譯時就已經確定了。也就是說:String s=A+B; 等同於:String s="ab"+"cd";
我對上面的例子稍加改變看看會出現什麼情況:
public class StringStaticTest {
public static final String A; // 常數A
public static final String B; // 常數B
static {
A = "ab";
B = "cd";
}
public static void main(String[] args) {
// 將兩個常數用+連接對s進行初始化
String s = A + B;
String t = "abcd";
if (s == t) {
System.out.println("s等於t,它們是同一個物件");
} else {
System.out.println("s不等於t,它們不是同一個物件");
}
}
}
它的運行結果是這樣:
s不等於t,它們不是同一個對象
只是做了一點改動,結果就跟剛剛的例子剛好相反。我們再來分析一下。 A和B雖然被定義為常數(只能被賦值一次),但是它們都沒有馬上被賦值。在運算出s的值之前,他們何時被賦值,以及被賦予什麼樣的值,都是個變數。因此A和B在被賦值之前,性質類似一個變數。那麼s就不能在編譯期被確定,而只能在執行時被創建了。
最後我們再來談談String物件在JAVA虛擬機器(JVM)中的存儲,以及字串池與堆疊(heap)和堆疊(stack)的關係。我們先回顧一下堆和棧的差別:
堆疊(stack):主要保存基本類型(或稱為內建型別)(char、byte、short、int、long、float、double、boolean)和物件的引用,資料可以共享,速度僅次於暫存器(register),快於堆。
堆(heap):用於儲存物件。
我們查看String類別的原始碼就會發現,它有一個value屬性,保存String物件的值,類型是char[],這也正說明了字串就是字元的序列。當執行String a="abc";時,JAVA虛擬機會在堆疊中建立三個char型的值'a'、'b'和'c',然後在堆中建立一個String對象,它的值(value )是剛才在堆疊中建立的三個char型值組成的陣列{'a','b','c'},最後這個新建立的String物件會被加入到字串池中。
如果我們接著執行String b=new String("abc");程式碼,由於"abc"已經被建立並保存於字串池中,因此JAVA虛擬機只會在堆中新建立一個String對象,但是它的值(value)是共用前一行程式碼執行時在堆疊中建立的三個char型值值'a'、'b'和'c'。
說到這裡,我們對於篇首提出的String str=new String("abc")為什麼是建立了兩個物件這個問題就已經相當明了。
本文來自CSDN博客,轉載請標示:http: //blog.csdn.net/yakihappy/archive/2009/03/10/3977169.aspx
本文出自CSDN博客,轉載請標示出處: http://blog.csdn.net/Foxalien/archive/2009/12/18/5029470.aspx
-