String的創建
String s = "hello";
JVM先根據內容"hello"查找對象,如果沒有找到,則在heap上創建新對象,並將其賦予s1,否則使用已經存在的對象
String s = newString("hello");
JVM直接在heap上創建新的對象,所以在heap中會出現內容相同,地址不同的String對象
String的比較
"==" 比較地址
"equals" 比較內容
舉例:
String s1 = "hello";
String s2 = "hello";
String s3 = new String("hello");
s1 ==s2; //true 地址相同
s1 ==s3; //false 地址不同
s1.equals(s2); //true 內容相同
s1.equals(s3); //true 內容相同
intern() 方法
查找內容相同(equals())的字符串
String s1 ="hello"; // hello不存在,jvm創建新對象 (1)
String s2 = newString("hello"); // 創舉新對象 (2),這時heap中存在兩個內容爲hello的對象
s1 ==s2; //false // 地址不同
s1.equals(s2); //true // 內容相同
s2 =s2.intern(); //true // 找到對象(1) 並賦予s2
s1 ==s2; // true!! // 注意:此時s1,s2同指向(1)
效率:String 與 StringBuffer
情景1:
(1) Stringresult = "hello" + " world";
(2)StringBuffer result = new String().append("hello").append("world");
(1) 的效率好於 (2),不要奇怪,這是因爲JVM會做如下處理
編譯前 String result = "hello"+ " world";
編譯後 String result = "helloworld";
情景2:
(1) publicString getString(String s1, String s2) {
return s1 + s2;
}
(2) publicString getString(String s1, String s2) {
return new StringBuffer().append(s1).append(s2);
}
(1) 的效率與 (2) 一樣,這是因爲JVM會做如下處理
編譯前 return s1 + s2;
編譯後 return newStringBuffer().append(s1).append(s2);
情景3:
(1) String s= "s1";
s += "s2";
s += "s3";
(2)StringBuffer s = newStringBuffer().append("s1").append("s2").append("s3");
(2)的效率好於(1),因爲String是不可變對象,每次"+="操作都會造成構造新的String對象
情景4:
(1)StringBuffer s = new StringBuffer();
for (int i = 0; i < 50000; i ++) {
s.append("hello");
}
(2)StringBuffer s = new StringBuffer(250000);
for (int i = 0; i < 50000; i ++) {
s.append("hello");
}
(2) 的效率好於(1),因爲StringBuffer內部實現是char數組,默認初始化長度爲16,每當字符串長度大於char
數組長度的時候,JVM會構造更大的新數組,並將原先的數組內容複製到新數組,(2)避免了複製數組的開銷
關鍵點
1). 簡單的認爲 .append() 效率好於 "+" 是錯誤的!
2). 不要使用new 創建 String
3). 注意.intern() 的使用
4).在編譯期能夠確定字符串值的情況下,使用"+"效率最高
5). 避免使用"+=" 來構造字符串
6).在聲明StringBuffer對象的時候,指定合適的capacity,不要使用默認值(18)
7).注意以下二者的區別不一樣
- String s = "a" + "b";
- String s = "a";
s += "b";
String和StringBuffer之概覽
創建字符串的較佳途徑
滯留字符串帶來的優化
連接字符串時的優化技巧
藉助StringBuffer的初始化過程的優化技巧
關鍵點
非可變對象一旦創建之後就不能再被改變,可變對象則可以在創建之後被改變。String對象是非可變對象,StringBuffer對象則是可變對象。爲獲得更佳的性能你需要根據實際情況小心謹慎地選擇到底使用這兩者中的某一個。下面的話題會作詳細的闡述。(注意:這個章節假設讀者已經具備Java的String和StringBuffer的相關基礎知識。)
1. String s1 ="hello";
String s2 ="hello";
2. String s3 = new String("hello");
String s4 =new String("hello");
StringTest1.java
* String literals and Stringobjects.
*/
longstartTime = System.currentTimeMillis();
for(inti=0;i<50000;i++){
String s2 ="hello";
}
System.out.println("Time taken for creation of String literals :"
+ (endTime - startTime) + " milli seconds" );
longstartTime1 = System.currentTimeMillis();
for(inti=0;i<50000;i++){
String s4 =new String("hello");
}
System.out.println("Time taken for creation of String objects :"
+ (endTime1 - startTime1)+" milli seconds");
}
}
這段代碼的輸出:
Time takenfor creation of String literals : 0 milli seconds
Time taken for creation of String objects : 170 milliseconds
Java虛擬機會維護一個內部的滯留字符串對象的列表(唯一字符串的池)來避免在堆內存中產生重複的String對象。當JVM從class文件里加載字符串字面量並執行的時候,它會先檢查一下當前的字符串是否已經存在於滯留字符串列表,如果已經存在,那就不會再創建一個新的String對象而是將引用指向已經存在的String對象,JVM會在內部爲字符串字面量作這種檢查,但並不會爲通過new關鍵字創建的String對象作這種檢查。當然你可以明確地使用String.intern()方法強制JVM爲通過new關鍵字創建的String對象作這樣的檢查。這樣可以強制JVM檢查內部列表而使用已有的String對象。