String、StringBuffer、StringBuilder有什麼區別?

java面試(二)-----String、StringBuffer、StringBuilder有什麼區別?

  • String :String是Java語言非常基礎和重要的類,提供了構造和管理字符串的各種基本邏輯。它是典型的Immutable類,被聲明成爲fnal class,所有屬性也都是fnal的。也由於它的不可變性,類似拼接、裁剪字符串等動作,都會產生新的String對象。由於字符串操作的普遍性,所以相關操作的效率往往對應用性能有明顯影響。
  • StringBuffer是爲解決上面提到拼接產生太多中間對象的問題而提供的一個類,我們可以用append或者add方法,把字符串添加到已有序列的末尾或者指定位置。StringBuffer本質是一個線程安全的可修改字符序列,它保證了線程安全,也隨之帶來了額外的性能開銷,所以除非有線程安全的需要,不然還是推薦使用它的後繼者,也就是StringBuilder。
  • StringBuilder是Java 1.5中新增的,在能力上和StringBuffer沒有本質區別,但是它去掉了線程安全的部分,有效減小了開銷,是絕大部分情況下進行字符串拼接的首選。

那麼 String 在內存中是以什麼形式存的呢?

jvm中的String

有兩種創建String字符串的方式,分別是
參考資料

  • String s1 = “1”;

  • String s2=new String(“1”);
    在這裏插入圖片描述如圖所示,當我們直接聲明一個字符串時,它是直接存在了常量池中,s1使用””引號(也是平時所說的字面量)創建字符串,在編譯期的時候就對常量池進行判斷是否存在該字符串,如果存在則不創建直接返回對象的引用;如果不存在,則先在常量池中創建該字符串實例再返回實例的引用給s1。注意:編譯期的常量池是靜態常量池

    s2使用關鍵詞new創建字符串,JVM會首先檢查字符串常量池,如果該字符串已經存在常量池中,那麼不再在字符串常量池創建該字符串對象,而直接堆中複製該對象的副本,然後將堆中對象的地址賦值給引用s2,如果字符串不存在常量池中,就會實例化該字符串並且將其放到常量池中,然後在堆中複製該對象的副本,然後將堆中對象的地址賦值給引用s2。注意:此時是運行期,那麼字符串常量池是在運行時常量池中的

其他

常量池(線程共享)

常量池則存在於方法區

常量池常被分爲兩大類:靜態常量池和運行時常量池。

靜態常量池也就是Class文件中的常量池,存在於Class文件中。

運行時常量池(Runtime Constant Pool)是方法區的一部分,存放一些運行時常量數據。

字符串常量池:

字符串常量池存在運行時常量池之中(在JDK7之前存在運行時常量池之中,在JDK7已經將其轉移到堆中)。

字符串常量池的存在使JVM提高了性能和減少了內存開銷。

使用字符串常量池,每當我們使用字面量(String s=”1”;)創建字符串常量時,JVM會首先檢查字符串常量池,如果該字符串已經存在常量池中,那麼就將此字符串對象的地址賦值給引用s(引用s在Java棧中)。如果字符串不存在常量池中,就會實例化該字符串並且將其放到常量池中,並將此字符串對象的地址賦值給引用s(引用s在Java棧中)。

使用字符串常量池,每當我們使用關鍵字new(String s=new String(”1”);)創建字符串常量時,JVM會首先檢查字符串常量池,如果該字符串已經存在常量池中,那麼不再在字符串常量池創建該字符串對象,而直接堆中複製該對象的副本,然後將堆中對象的地址賦值給引用s,如果字符串不存在常量池中,就會實例化該字符串並且將其放到常量池中,然後在堆中複製該對象的副本,然後將堆中對象的地址賦值給引用。

問題:

  1. 如何判斷常量池中是否已經存在某個字符
    答:有intern() 方法,該方法是一個Native方法,底層調用C++的 StringTable::intern方法實現
    String.intern()是一個Native方法,底層調用C++的 StringTable::intern方法實現。當通過語句str.intern()調用intern()方法後,JVM 就會在當前類的常量池中查找是否存在與str等值的String,若存在則直接返回常量池中相應Strnig的引用;若不存在,則會在常量池中創建一個等值的String,然後返回這個String在常量池中的引用。因此,只要是等值的String對象,使用intern()方法返回的都是常量池中同一個String引用,所以,這些等值的String對象通過intern()後使用==是可以匹配的。

  2. 將String修改其他值或置爲null後會發生什麼?
    答:當String修改其他值後,String的字面量就直接指向了新修改的值的引用,原來舊的值仍然存在於字符串常量池中,若沒有其他引用指向它就會直接等待垃圾回收。置爲null也是如此,字面量沒有任何引用,原來的值仍然存在於字符串常量池中,若沒有其他引用指向它就會直接等待垃圾回收。
    參考資料

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章