在java語言中,字元串起着非常重要的作用,字元串的聲明與初始化主要有如下兩種情況:
(1) 對于string s1=new string(“abc”)語句與string s2=new string(“abc”)語句,存在兩個引用對象s1、s2,兩個内容相同的字元串對象”abc”,它們在記憶體中的位址是不同的。隻要用到new總會生成新的對象。
(2) 對于string s1 = “abc”語句與string s2 = “abc”語句,在jvm中存在着一個字元串池,其中儲存着很多string對象,并且可以被共享使用,s1、s2引用的是同一個常量池中的對象。由于string的實作采用了flyweight的設計模式,當建立一個字元串常量的時候,例如string s = “abc”,會首先在字元串常量池中查找是否已經有相同的字元串被定義,它的判斷依據是string類equals(object obj)方法的傳回值。如果已經定義,則直接擷取對其的引用,此時不需要建立新的對象,如果沒有定義,則首先建立這個對象,然後把它加入到字元串池中,再将它的引用傳回。由于string是不可變類,一旦建立好了就不能被修改,是以string對象可以被共享而且不會導緻程式的混亂。
具體而言:
string s=“abc”; //把“abc”放到常量區中,在編譯時産生。
string s=“ab”+”c”; //把“ab”+“c”轉換為字元串常量“abc”放到常量區中。
string s=new string(“abc”); //在運作時把“abc”放到堆裡面的。
例如:
string s1=“abc”; //在常量區裡面存放了一個”abc”字元串對象string s2=“abc”; //s2引用常量區中的對象,是以不會建立新的對象
string s3=new string(“abc”) //在堆中建立新的對象
string s4=new string(“abc”) //在堆中又建立一個新的對象
為了便于了解,可以把string s = new string(“abc”)語句的執行人為地分解成兩個過程:第一個過程是建立對象的過程,即new string(“abc”),第二個過程是指派的過程,即string s=。由于第二個過程中隻是定義了一個名為s的string類型的變量,将一個string類型對象的引用指派給s,是以在這個過程中不會建立新的對象。第一個過程中new string(“abc”)會調用string類的構造函數:
public string(string original){
//body
}
在調用這個構造函數的時候,傳入了一個字元串常量,是以語句new string(“abc”)也就等價于”abc”和new string()兩個操作了。如果在字元串池中不存在”abc”,則會建立一個字元串常量”abc”,并将其添加到字元串池中,如果存在,則不建立,然後new string()會在堆中建立一個新的對象。是以str3與str4指向的是堆中不同的string對象,位址自然也不相同了。如下圖所示。
引申:對于string類型的變量s,指派語句s=null與s=“”是否相同?
對于指派語句s=null,其中s是一個字元串類型的引用,它不指向任何一個字元串。而指派語句s=“”中 s是一個字元串類型的引用,它指向另外一個字元串(這個字元串的值為“”,即空字元串)。
常見筆試題:
new string(“abc”)建立了幾個對象?
答案:一個或兩個。如果常量池中原來有“abc”,那麼隻建立一個對象,如果常量池中原來沒有字元串“abc”,那麼就會建立兩個對象。
出自:http://www.360jobhunting.com/?p=149