Java String是一個「不可變常量字符串」對象,final屬性定義。之因此這麼說,是從String內部在盛放字符串時候的容器char數組而言。好比當用戶在初始化階段定義了一個String對象String s=」hello,world!」,而此時再次對s進行操做改變s的值時候,如再次給s賦值使得s=」zhangphil」,那麼Java的JVM實際上是再次建立了一個新的String對象,而後移動指針s指向了新的String對象(對象內部的字符串是「zhangphil」)。因而可知,假如在代碼中須要頻繁的修改String對象中的字符內容,那麼應該儘可能避免使用String,緣由在於每一次修改String內容後,其實就是JVM在內存堆上建立了一個新的String對象,由此致使的問題有三:
(一)若是代碼中的String對象頻繁的修改,表面仍然是在一個String對象中修改賦值,但其實底層的JavaJVM在內存的堆上建立了更多新的String對象,同時與之相伴隨的是更多死去的String對象,此過程簡單總結就是Java JVM在頻繁的建立對象,也產生死去的對象,即,生成一個新的String對象,死去一個String對象。這樣將產生大量JVM內存碎片,極大機率提升Java了系統觸發Java GC的時機,由此下降了系統性能 。
(二)String對象的產生、賦值修改操做過程是多線程不安全操做,緣由如前所述,每一次對String對象的賦值、操做,致使Java JVM在底層建立了新的String對象,在操做系統的CPU時機片上,線程不保證安全。若是多線程在操做此String對象,那麼就極有可能在操做系統調度切換CPU時間片時,操做的目標對象不一致,有的指向新的String s對象,有的線程卻仍指向舊的String s對象。
(三)每一次修改賦值String s對象,是建立了新的String對象,而後把新的對象引用賦給s。這個操做是在堆上建立 ,若頻繁操做,勢必形成較大系統開銷。
小結:若是是在代碼啓動後,String對象再也不修改從新賦值,那麼能夠考慮使用String,好比在代碼中定義一些public static final String常量。若是須要在代碼中頻繁修改和賦值操做字符串對象具體內容,建議使用StringBuffer。
不一樣於String字符串常量,StringBuffer是字符串變量。StringBuffer不會產生String那樣的問題:每一次修改就從新建立一個新的String對象。在某種程度上講,StringBuffer內部維持一個可變長度的char數組盛放用戶字符數據,所以StringBuffer是線程安全的。因爲StringBuffer是在一個字符char數組進行原子賦值、操做,不是像String那樣以「乾坤大挪移」的方式改變引用進行字符串賦值、操做,在理論上講,字符的操做層面,StringBuffer的性能優於String。
StringBuilder是在後續新版Java中引入的字符類,StringBuilder和StringBuffer相似,均是字符串變量,可是StringBuilder多線程不安全,而單線程安全,StringBuilder在單線程中性能優於StringBuffer,所,若是僅僅是在單線程中使用字符串變量,優先可考慮使用StringBuilder。數組