String、StringBuilder、StringBuffer 使用場景
當字元串相加操作或者改動較少的情況下,建議使用 String str="hello"這種形式;
當字元串相加操作較多的情況下,建議使用StringBuilder,如果采用了多線程,則使用StringBuffer。
編譯期間優化字元串相加操作
"I"+"love"+"java"; 的字元串相加,在編譯期間便被優化成了"Ilovejava"
String str = "hello"+ "world"的效率就比 StringBuilder st = new StringBuilder().append("hello").append("world")要高
String 如何存儲在記憶體?
在java中,記憶體分成兩個區域stack 和 heap , stack 用于運作(包括變量引用和邏輯運作),heap 用于存儲變量實體。
java中對String對象特殊對待,是以在heap區域分成了兩塊:
1. 一塊是String constant pool,用于存儲java字元串常量對象
2. 另一塊用于存儲普通對象及字元串對象
面試題(轉自:cnblog 海子):
1. 下面這段代碼的輸出結果是什麼?
String a = "hello2"; String b = "hello" + 2; System.out.println((a == b));
輸出結果為:true。原因很簡單,
"hello"+2在編譯期間就已經被優化成"hello2",是以在運作期間,變量a和變量b指向的是同一個對象。
2.下面這段代碼的輸出結果是什麼?
String a = "hello2"; String b = "hello"; String c = b + 2; System.out.println((a == c));
輸出結果為:false。
由于有符号引用的存在,是以 String c = b + 2;不會在編譯期間被優化,不會把b+2當做字面常量來處理的,是以這種方式生成的對象事實上是儲存在堆上的。是以a和c指向的并不是同一個對象。
3.下面這段代碼的輸出結果是什麼?
String a = "hello2"; final String b = "hello"; String c = b + 2; System.out.println((a == c));
輸出結果為:true。
對于被final修飾的變量,會在class檔案常量池中儲存一個副本,也就是說不會通過連接配接而進行通路,對final變量的通路在編譯期間都會直接被替代為真實的值。那麼String c = b + 2;
在編譯期間就會被優化成:String c = "hello" + 2
4.下面這段代碼輸出結果為:
public class Main {
public static void main(String[] args) {
String a = "hello2";
final String b = getHello();
String c = b + 2;
System.out.println((a == c));
}
public static String getHello() {
return "hello";
}
}
輸出結果為false。
這裡面雖然将b用final修飾了,但是由于其指派是通過方法調用傳回的,那麼它的值隻能在運作期間确定,是以a和c指向的不是同一個對象。
5. String str = new String("abc")建立了多少個對象?
而這道題目讓人混淆的地方就是這裡,這段代碼在運作期間确實隻建立了一個對象,即在堆上建立了"abc"對象。而為什麼大家都在說是2個對象呢,這裡面要澄清一個概念 該段代碼執行過程和類的加載過程是有差別的。在類加載的過程中,确實在運作時常量池中建立了一個"abc"對象,而在代碼執行過程中确實隻建立了一個String對象。
是以,這個問題如果換成 String str = new String("abc")涉及到幾個String對象?合理的解釋是2個。
個人覺得在面試的時候如果遇到這個問題,可以向面試官詢問清楚”是這段代碼執行過程中建立了多少個對象還是涉及到多少個對象“再根據具體的來進行回答。
6. 下面這段代碼1)和2)的差別是什麼?
public class Main {
public static void main(String[] args) {
String str1 = "I";
//str1 += "love"+"java"; 1)
str1 = str1+"love"+"java"; //2)
}
}
1)的效率比2)的效率要高,
1)中的"love"+"java"在編譯期間會被優化成"lovejava",而2)中的不會被優化