標籤:
Java中的字串常量
Java中的字串是不可改變的,當然,它與字串常量,比如:
public static final String a="123";
是不同的,此處指的是a只能指向字串123,而我們今天指的不可改變指的是字串在記憶體中不可變,現在我們看一個例子:
package com.test;/** * Created by siege on 2015-08-02. */public class TestString { public static void main(String[] args) { String a="0"; for (int i = 1; i <10 ; i++) { a+=i; System.out.println(a); } }}
其輸出結果為:
01
012
0123
01234
012345
0123456
01234567
012345678
0123456789
當然,結果並不奇怪,表面上看起來,a的值一直在變,好像a最初指向的“0”變成了"0123456789",其實不是這樣的,實際上上述的字串都存在記憶體中,只不過a的引用一直在變。
實際上,在java中存在一個字串池(String pool,由JVM維護),當我們給變數a賦值一個字串時(比如”0”),首先,JVM會在String pool中找是否有”0”這個字串,如果有,那麼直接將該字串在String pool中的引用返回,使a指向這個引用,如果沒有的話,那麼建立該字串,然後將該字串的引用返回給a,舉例說明:
package com.test;/** * Created by siege on 2015-08-02. */public class TestString { public static void main(String[] args) { String a="hello"; String b="hello"; System.out.println(a==b); }}
其結果為true,這就說明了a和b指向的是同一個字串的引用,但是如果我們這樣建立:
package com.test;/** * Created by siege on 2015-08-02. */public class TestString { public static void main(String[] args) { String a="hello"; String b=new String("hello"); System.out.println(a==b); }}
其結果為false,究其原因,使用new建立的字串對象是存在堆中的,故他們的地址不同。繼續看:
public class TestString { public static void main(String[] args) { String a="abc"; String b="edf"; String c=a+b; System.out.println(c=="abcdef"); }}
其結果為false,這說明了c指向的是堆記憶體中的”abcdef”,不信我們繼續看:
public class TestString { public static void main(String[] args) { String a="abc"; String b="edf"; String c=a+b; String d="abcdef"; System.out.println(c==d); }}
其結果也為false,這樣就證明了c指向的並不是String pool中的常量”abcdef”,那麼它必然是指向堆中的”abcdef”,進一步深入,實際上 String a="abc" 在編譯期間JVM就已經將a變數的值”abc”放入String pool中了,String c=a+b只有在運行期間才能知道c的值,故其是在堆中建立的,在堆中建立的還有兩個String對象,a和b,他們是將String pool中的a,b的值賦值到堆中去的,在堆中建立兩個對象,然後建立對象c,將"abcdef" 的堆地址賦給c。
public class TestString { public static void main(String[] args) { String a="abc"+"def"; System.out.println(a=="abcdef"); }}
輸出結果為true,說明JVM是將"abcdef" 放入String pool中的。
public class TestString { public static void main(String[] args) { String a="abc"; String b=a+"def"; System.out.println(b=="abcdef"); }}
其結果為false,這也說明了b是在堆中建立的。
public class TestString { public static void main(String[] args) { String a=new String("abc"); String b=a.intern(); String c="abc"; System.out.println(b==c); }}
intern()方法是將堆中建立的a對象的字串放入到String pool,不過在放入之前先檢查是否有改字串,有的話就無需放入,沒有的話就將其放入String pool中,並將其引用返回給b。故上述結果為true。
關於設定String pool’的意義在於減少相同內容字串的建立,節省記憶體空間,缺點就是在存放字串到String pool中是需要進行計算該String pool中是否已經有該字串了。
著作權聲明:本文為博主原創文章,未經博主允許不得轉載。
Java中的字串