下面小編就為大家帶來一篇老生常談Java String字串(必看篇)。小編覺得蠻不錯的,現在就分享給大家,也給大家做個參考。一起跟著小編過來看看吧
Java中字串物件建立有兩種形式,一種是字面量形式,如String str = "hello";,另一種就是使用new這種標準的建構物件的方法,如String str = new String("hello");
對於這樣的常識,不再贅述。
首先String類別是final類,為什麼定義成final形式呢?
簡單說,對於如此高頻率被使用的資料類型,設計者們認為已經設計的足夠優秀了,不需要被繼承,否則胡亂繼承重寫可能會降低程式的性能。
如標題所述,既然深入,那我們就挖下String在jvm層面的小動作。
先解釋字面量創建的形式:
#當程式碼中出現字面量形式建立字串物件時,JVM首先會對這個字面量進行檢查,如果字串常數池中存在相同內容的字串物件的引用,則將這個引用返回,否則新的字串物件被創建,然後將這個引用放入字串常數池,並返回該引用。
如下:
String str1 = "hello" ;
當我們第一次創建的時候,這裡我們認為沒有內容為hello的物件存在。 JVM透過字串常數池查找不到內容為hello的字串物件存在,那麼會建立這個字串對象,然後將剛建立的物件的引用放入到字串常數池中,並且將引用傳回給變數str1
如果接下來有這樣一段程式碼
String str2 = "hello" ;
同樣JVM還是要偵測這個字面量,JVM透過找出字串常數池,發現內容為」hello」字串物件存在,於是將已經存在的字串物件的參考傳回給變數str2。注意這裡不會重新建立新的字串物件。
驗證是否為str1和str2是否指向同一對象,我們可以透過這段程式碼
System.out.println(str1 == str2);
結果為true。
第二個使用new建立:
String str3 = new String("hello");
當我們使用了new來建構字串物件的時候,不管字串常數池中有沒有相同內容的物件的引用,新的字串物件都會創建。因此我們使用下面程式碼測試一下,
String str3 = new String("hello"); System.out.println(str1 == str3);
結果為false。說明這兩個引用指向不同的物件。
intern
對於上面使用new建立的字串對象,如果想將這個物件的參考加入到字串常數池,可以使用intern方法。
呼叫intern後,首先檢查字串常數池中是否有該物件的引用,如果存在,則將這個引用傳回給變量,否則將引用加入並傳回給變數。
String str4 = str3.intern(); System.out.println(str4 == str1);
結果為true。
疑難問題
前提條件?
字串常數池實作的前提條件就是Java中String物件是不可變的,這樣可以安全地保證多個變數共享同一個物件。如果Java中的String物件可變的話,一個引用運算改變了物件的值,那麼其他的變數也會受到影響,顯然這樣是不合理的。
引用 or 物件
字串常數池中存放的時引用還是對象,這個問題是最常見的。字串常數池存放的是物件引用,不是物件。在Java中,物件都創建在堆疊記憶體中。字串常數池存在於堆記憶體中的永久代
優缺點
字串常數池的好處就是減少相同內容字串的創建,節省記憶體空間。
如果硬要說弊端的話,就是犧牲了CPU運算時間來換空間。 CPU計算時間主要用於在字串常數池中尋找是否有對內容相同物件的參考。不過其內部實作為HashTable,所以計算成本較低。
GC回收?
因為字串常數池中持有了共享的字串物件的引用,這就是說是不是會導致這些物件無法回收?
首先問題中共享的物件一般情況下都比較小。據我查證了解,在早期的版本中確實存在這樣的問題,但是隨著弱引用的引入,目前這個問題應該沒有了。
intern使用?
#关于使用intern的前提就是你清楚自己确实需要使用。比如,我们这里有一份上百万的记录,其中记录的某个值多次为美国加利福尼亚州,我们不想创建上百万条这样的字符串对象,我们可以使用intern只在内存中保留一份即可。
总有例外?
你知道下面的代码,会创建几个字符串对象,在字符串常量池中保存几个引用么?
String test = "a" + "b" + "c";
答案是只创建了一个对象,在常量池中也只保存一个引用。我们使用javap反编译看一下即可得知。
实际上在编译期间,已经将这三个字面量合成了一个。这样做实际上是一种优化,避免了创建多余的字符串对象,也没有发生字符串拼接问题。
以上是Java中關於String字串的詳細介紹的詳細內容。更多資訊請關注PHP中文網其他相關文章!