一梧兼、Define
- String: 字符串常量
- StringBuffer: 字符串變量(線程安全)
- StringBuilder: 字符串變量(非線程安全)
二、 Explanation
1. String 是不可變類型乍炉,每改變一次String對象的值==聲明一個String對象馋贤,然后將該引用地址指向新的String對象赞别。這是因為String被聲明為Final class,其所有屬性也被final修飾配乓,故對于String的拼接仿滔、剪裁都必須以生成新的String對象完成,不可變模式主要在于一個String對象需要被多線程共享時犹芹,省略同步和鎖的時間開銷崎页,提高系統性能并降低多線程開發(fā)的復雜度。但需要經常改變內容時腰埂,不要使用String類型飒焦。
2. StringBuffer相對于String類型,對其修改只對 StringBuffer 對象本身進行操作屿笼,而不生成新的StringBuffer牺荠,例如使用append()、add()等方法將字符添加到目標位置驴一。StringBuffer的實現是線程安全的(synchronize)休雌,所以會用性能方面的開銷,故沒有線程安全的需要時蛔趴,使用StringBuilder的性能更好挑辆。
3. StringBuilder的是進行頻繁字符串拼接的首選類型例朱,是非線程安全的StringBuffer孝情。兩者都繼承自AbstractStringBuilder鱼蝉,區(qū)別僅在于StringBuffer的方法加上了Synchronize修飾。
StringBuffer/StringBuilder 內部由數組實現(char箫荡,JDK9 使用byte)魁亦,且初始長度為16,可以通過合理的長度估計羔挡,指定其大小以避免擴容和arraycopy導致的性能開銷洁奈。當然,char占用2個字節(jié)绞灼,故同樣數組長度下利术,JDK9中使用byte使存儲能力退化了一倍。
三低矮、Example
1.字符串的構造
在實際使用中印叁,JVM通常將String解釋成StringBuffer對象進行拼接,所以這些時候 String 對象的速度并不會比 StringBuffer 對象慢军掂。而像以下的字符串對象的聲明時轮蜕, String 效率 StringBuffer 還要快:
String S1 = “This is only a” + “ simple” + “ test”;
StringBuffer Sb = new StringBuffer(“This is only a”).append(“ simple”).append(“ test”);
在這種情況下,JVM直接將
String s = "This is only a" + " simple" + " test"
等同于構造為
String ss = "This is only a simple test"
即 s==ss 返回的是true蝗锥;
但是跃洛,如果被拼接的字符串是來自另外的 String 對象,譬如:
String S2 = “This is only a”;
String S3 = “ simple”;
String S4 = “ test”;
String S1 = S2 +S3 + S4;
JVM 按照StringBuffer方式進行拼接终议。
在JDk9中javac提供了 StringConcatFactory作為統一入口處理字符串汇竭。
2.字符串緩存
Java6后提供了intern()方法提示JVM將相應的字符串緩存以備重復利用,在創(chuàng)建字符串對象時調用intern()方法會檢查已存在常量池中的字符串穴张,并返回已存在的實例细燎。而且常量池被存儲在永久代中,并不會被GC回收陆馁。
Java8中被改為存儲在MetaSpace中找颓,緩存大小也在一直變大。8u20后JVM會將相同數據的字符串指向同一數據地址叮贩。(需使用G1 GC)
StringBuffer 的append 和 insert 方法會將新的字符串常量加入的常量池中
例如:
StringBuffer sb = new StringBuffer(“Joe”);
sb.append(" Blake");
sb.inset(3," Blake")击狮;
均會使常量池中加入“Joe Blake”。