使用Java語言進行編程食听,我們每天都要用到String類奸披,但是以前只是拿來就用邻寿,并不知道String類的實現(xiàn)原理和在內(nèi)存中是如何存在的蝎土,所以,是時候來仔細看看我們熟悉的String背后的故事了绣否。
1.Java內(nèi)存模型-常量池
方法區(qū)(Method area)
(1)保存被加載類型的信息誊涯,包括類型信息(Type Information)和方法列表(Method Tables)。
(2)所有線程共享蒜撮,所以訪問方法區(qū)信息的方法必須是線程安全的搀罢。
(3)在JVM啟動的時候創(chuàng)建卖哎。
(4)存儲了每個類的結(jié)構(gòu)信息为迈,例如運行時常量池(Runtime Constant Pool)拾枣、字段和方法數(shù)據(jù)庆械、構(gòu)造函數(shù)和普通方法的字節(jié)碼內(nèi)容薇溃、還包括一些在類、實例缭乘、接口初始化時用到的特殊方法沐序。
運行時常量池(Runtime constant pool)
位于方法區(qū)中琉用,是每一個類或接口的常量池(Constant_Pool)的運行時表現(xiàn)形式,它包括了若干種常量:編譯器可知的數(shù)值字面量到必須運行期解析后才能獲得的方法或字段的引用策幼。
簡而言之邑时,當一個方法或者變量被引用時,JVM通過運行時常量區(qū)來查找方法或者變量在內(nèi)存里的實際地址特姐。
在類和接口被加載到JVM后晶丘,對應(yīng)的運行時常量池就被創(chuàng)建。
2.String連接案例解析
String常量
-
String常量的值是在常量池中的
JVM中的常量池在內(nèi)存當中是以表(hashtable)的形式存在的唐含, 對于String類型浅浮,有一張固定長度的CONSTANT_String_info表用來存儲文字字符串值,注意:該表只存儲文字字符串值捷枯,不存儲符號引用滚秩。
常量池中保存著很多String對象,并且可以被共享使用淮捆,因此它提高了效率郁油。
-
在Java中,String對象是不可變的(Immutable)
在代碼中,可以創(chuàng)建多個某一個String對象的別名攀痊,但是這些別名的引用是相同的桐腌。
String的連接
-
JAVA虛擬機處理String的連接符+(concatenation)時會有不同處理
如果都是字符常量,那么只會生成一個蚕苇。
如果有變量哩掺,那么會調(diào)用StringBuilder,最后調(diào)用Sb的tostring涩笤。
連接符兩邊只要有一個不是字符串常量嚼吞,那就是說明那個變量是個地址的引用,引用指向的值編譯時無法知道的蹬碧。
String a = "123" (生成一個字符串常量)
String a = "123" + b (調(diào)用StringBuilder)
-
String a="a"+"b"+"c"在內(nèi)存中創(chuàng)建幾個對象舱禽?
甲骨文jdk(1.7),javac會進行常量折疊恩沽,全字面量字符串相加是可以折疊為一個字面常量誊稚,而且是進入常量池的。
優(yōu)化進行在編譯器編譯.java到bytecode時罗心,通過編譯器優(yōu)化后里伯,得到的效果是String a="abc" 。此時渤闷,如果字符串常量池中存在abc疾瓮,則該語句并不會創(chuàng)建對象,只是講字符串常量池中的引用返回而已飒箭。
字符串常量池存放的是對象引用狼电,不是對象蜒灰。在Java中,對象都創(chuàng)建在堆內(nèi)存中肩碟。
如果字符串常量池中不存在abc强窖,則會創(chuàng)建并放入字符串常量池,并返回引用削祈,此時會有一個對象進行創(chuàng)建翅溺。
-
String.intern()
String對象的實例調(diào)用intern方法后,可以讓JVM檢查常量池岩瘦,如果沒有實例的value屬性對應(yīng)的字符串序列比如"123"(注意是檢查字符串序列而不是檢查實例本身)未巫,就將本實例放入常量池,如果有當前實例的value屬性對應(yīng)的字符串序列"123"在常量池中存在启昧,則返回常量池中"123"對應(yīng)的實例的引用而不是當前實例的引用叙凡,即使當前實例的value也是"123"。
3.優(yōu)缺點
字符串常量池的好處就是減少相同內(nèi)容字符串的創(chuàng)建密末,節(jié)省內(nèi)存空間握爷。
如果硬要說弊端的話,就是犧牲了CPU計算時間來換空間严里。CPU計算時間主要用于在字符串常量池中查找是否有內(nèi)容相同對象的引用新啼。不過其內(nèi)部實現(xiàn)為HashTable,所以計算成本較低刹碾。
4.StringBuffer和StringBuilder
StringBuffer 始于 JDK 1.0
StringBuilder 始于 JDK 1.5
從 JDK 1.5 開始燥撞,帶有字符串變量的連接操作(+),JVM 內(nèi)部采用的是StringBuilder 來實現(xiàn)的迷帜,而之前這個操作是采用 StringBuffer 實現(xiàn)的物舒。
參考:
http://www.pellegrino.link/2015/08/22/string-concatenation-with-java-8.html
http://www.cnblogs.com/ITtangtang/p/3976820.html
http://www.cnblogs.com/jmzz/archive/2011/08/24/2151450.html
http://gityuan.com/2016/01/09/java-memory/
http://droidyue.com/blog/2014/08/30/java-details-string-concatenation/
http://www.reibang.com/p/380fa5c92dcc