final修飾的特點
衆所周知Java的String類是被final所修飾的,所以我們不僅要產生一個疑問爲什麼要用final修飾呢?
- final修飾代表了其具有不可變性,一旦賦值將不可更
- String天然具有線程安全的特性,
- String雖不是基本變量,使用頻率卻不比基本變量低,其不可變性可以極大程度的提高其複用性,比如intern方法
- 保證了hashcode的唯一性,從而奠定了hashmap的k-v基石
String各個版本的改動及特點
sun對string字符串的優化也是不遺餘力的,
1、Java6 String包含 char[]、offset、count、hashcode
Java6中主要通過offset\count記錄字符串的實際內容,char有可能是其他對象的數組,該版本的String的substring是極其有可能引起內存泄漏的,
- substring返回的對象的char[]數組是上一個對象的char數組的引用,這就可能引發一下兩個問題,因爲該對象保持着上一個對象的引用,所以上個String對象將不對被GC回收;
- 如果上個對形象的char數組非常大,但是真正substring後使用的只是其中的一兩個字符,同時還要在內存中維護着這個超長的數組,從而造成了內存空間的浪費.具體可參考1.6的源碼
2、Java7-8 String包含 char[]、hashcode
Java7後去掉了6中的offset、count減少了一點點的內存,同時也解決了java6中substing導致內存泄漏的弊端,因爲調用了底層的數組copy的本地方法,不再維護上個對象的char數組的應用,已保存了自身的string的字符數組
3、Java9 String包含 byte[]、coder、hashcode
Java9再次對String做出了更高的優化,將char[]數組替換成了byte[]數組,同時新增了coder的屬性,此次優化的點在於將char數組換成了byte數組,內存的控制更加的精細了,因爲char是16位佔2個字節,但除了漢字,數字、字母都佔用一個字節,所以使用char存放字母與數字內存使用率還是比較低的,而新增的coder屬性就是區分這個的0按照一個字節計算長度,1按照兩個字節計算長度從而達到更加合理的使用內存的目的
String優化點
1、String對象的創建分兩種方式
1)String str = "abc"
2) String str = new String("abc")
第一種方式JVM首先會在常量池中查看是否存在該字符串對象如果存在則直接返回常量池的引用,從而避免重複的創建對象
第二種方式在編譯類的時候會將"abc"字符串放入常量結構中,在類加載期間,會在常量池中創建,最後再調用new的構造函數時返回abc的應用,完成在堆上對象的創建,並將地址返回給str引用。
2、淺談String str = "a" + "b" + "c"與 String a = "a"; String str = a + "bc";
第一種理論上應該是先產生 a、ab、abc這三個對象的;但是實際上只產生了”abc"這一個對象,由編譯後的文件可是java在編譯期對string做了優化,所以只產生了一個對象
第二種編譯期同樣做出了相應的優化內容爲: str = (new StringBuilder("a")).append("bc")
所以說針對字符串常量的拼接,尤其是在循環中,爲了避免過段創建對象,最好還是使用StringBuilder做字符串的拼接,更有利於程序的穩定運行。
3、利用intern節約內存
針對使用多且長的字符串,可以做一些有效的拆分,從而達到最大程度複用字符串節約內存的目的 ;比如地址:“北京通州永順翠福園小區” 這個串如果此類地址過多的話可以考慮針對省、市等常用地名做拆分操作,避免重複的保存過多的字符串造成內存的浪費
如下對象
public class Location {
private String city;
private String region;
private String countryCode;
private double longitude;
private double latitude;
}
對city的賦值可以是使用"北京".intern() 這樣所有的北京字段再內存中就會佔用一份內存,從而避免了創建過多的包含北京字符串的對象,達到節約內存的目的。
案例來自一位 Twitter 工程師在 QCon 全球軟件開發大會上的演講他們想到的解決方法,就是使用 String.intern 來節省內存空間,從而優化 String 對象的存儲。具體做法就是,在每次賦值的時候使用 String 的 intern 方法,如果常量池中有相同值,就會重複使用該對象,返回對象引用,這樣一開始的對象就可以被回收掉。這種方式可以使重複性非常高的地址信息存儲大小從 20G 降到幾百兆。