String 簡述及intern方法
https://docs.oracle.com/javase/8/docs/api/java/lang/String.html
在JAVA中有8種基本型別和一種特殊字元型別:String。這些型別為了執行更快,更節省記憶體,使用了常量池的概念。
String宣告為final,表示不可繼承,所有的屬性也是final型別。字串常量:string一經建立值便不可修改。由於它的不可變性,因此string相關的拼接,擷取等操作都會產生新的物件。String底層使用char陣列方式進行儲存。
常見生成string方式:
1、String s = new String("abc"); 建立了二個物件:1、第一個物件 "abc"對應常量池中;第二個物件 在JAVA heap中的String物件。
2、String a = "11"; 宣告使用雙引號直接儲存到常量池中。
3、String.valueOf(1); 底層使用new String(char[])的方式實現轉換
String#intern方法
native String intern():目的是提示 JVM 把相應字串快取起來,以備重複使用。。
intern() 是一種顯式排重的機制。需要使用者顯式呼叫它,這樣一是不方便,二是每次顯式比較麻煩。
要注意的是,String的String Pool是一個固定大小的Hashtable,預設值大小長度是1009,如果放進String Pool的String非常多,就會造成Hash衝突嚴重,從而導致連結串列會很長,而連結串列長了後直接會造成的影響就是當呼叫String.intern時效能會大幅下降(因為要一個一個找)。
在 jdk6中StringTable是固定的,就是1009的長度,所以如果常量池中的字串過多就會導致效率下降很快。
在jdk7中,StringTable的長度可以通過一個引數指定: -XX:StringTableSize=99991
1 public static void main(String[] args) { 2 String s1 = new String("1"); 3 String s2 = "1"; 4 s1.intern(); 5 System.out.println(s1 == s2); 6 7String s3 = new String("1") + new String("2"); 8 String s4 = "12"; 9 s3.intern(); 10 System.out.println(s3 == s4); 11 }
輸出結果: false false
程式碼行7:生成兩個物件,分別對應常量池"1","2", JAVA heap中的s3引用指向的物件。 s3引用指向物件的內容是"12",但是此時常量池中沒"12"物件。"Java語言為字串連線運算子(+)以及將其他物件轉換為字串提供了特殊的支援。字串連線是通過StringBuilder(或StringBuffer)類及其append方法實現的。字串轉換是通過toString方法實現的"
程式碼行8:s4是顯式宣告,直接向常量池查詢不到,則建立物件。
程式碼行9:intern()返回字串物件的規範表示形式。在呼叫intern方法時,如果池中已經包含了由equals(object)方法確定的與該字串物件相等的字串,則返回池中的字串。否則,該字串物件將被新增到池中,並返回對該字串物件的引用。
如果s4 變換下位置
1 public static void main(String[] args) { 2 String s = new String("1"); 3 String s2 = "1"; 4 s.intern(); 5 System.out.println(s == s2); 6 7 String s3 = new String("1") + new String("2"); 8 s3.intern(); 9 String s4 = "12"; 10 System.out.println(s3 == s4); 11 }
輸出結果: false true (以上基於jdk8執行)
程式碼行8:先呼叫intern(),會在常量池建立物件並返回物件引用。
程式碼行9:s4宣告式顯示,在常量池中找到並返回物件。
因此,s3==s4是指向同一個物件。