【005期】JavaSE面試題(五):String類

開篇介紹

大家好,我是Java最全面試題庫的提褲姐,本篇文章是面試系列文章的第五篇,主要介紹了JavaSE中String相關的面試題,在之後會順着開篇的思維導圖一直總結下去,做到日更!如果我能做到百日百更,希望你也可以跟着百日百刷,一百天養成一個好習慣。

一、String、StringBuffer、StringBuilder 的區別?

  • 都是final類,都不允許被繼承
  • String長度是不可變的,StringBuffer和StringBuilder長度是可變的。
  • StringBuffer是線程安全的,StringBuilder是線程不安全的,但他們兩個中的所有方法都是相同的,StringBuffer在StringBuilder的方法之上加了synchronized修飾,保證線程安全。
  • StringBuilder比StringBuffer擁有更好的性能。
  • 如果一個String類型的字符串,在編譯時就可以確定是一個字符串常量,則編譯完成之後,字符串會自動拼接成一個常量。此時String的速度比StringBuilder和StringBuffer的性能更好。

二、String str=“aaa” 與 String str=new String(“aaa”)一樣嗎?

不同,內存分配的方式不同。
String str="aaa",創建了1個對象,創建的"aaa"是常量,jvm將其分配在常量池中;
String str=new String("aaa"),創建了2個對象,一個是在常量池中,一個在堆內存中。

三、String str=“aa” ,String s=“bb” ,String aa=aa+s;一共創建了幾個對象?

一共有2個引用,3個對象;
“aa"與"bb"都是常量,常量的值不能改變,當執行字符串拼接的時候,會創建一個新的常量"aabb”,將其存到常量池中。

四、String s = “Hello”;s = s + " world!";這兩行代碼執行後,原始的 String 對象中的內容到底變了沒有?

沒有。
因爲 String 被設計成不可變(immutable)類,所以它的所有對象都是不可變對象。在這段代碼中,s 原先指
向一個 String 對象,內容是 “Hello”,然後我們對 s 進行了“+”操作,那麼 s 所指向的那個對象是沒有發生變化的。這時,s 不指向原來那個對象了,而指向了另一個 String 對象,內容爲"Hello world!",原來那個對象還存在於內存之中,只是 s 這個引用變量不再指向它了。
結論,如果經常對字符串進行各種各樣的修改,或者說,不可預見的修改,那麼使用 String 來代表字符串的話會引起很大的內存開銷。因爲 String 對象建立之後不能再改變,所以對於每一個不同的字符串,都需要一個 String 對象來表示。這時,應該考慮使用 StringBuffer 類,它允許修改,而不是每個不同的字符串都要生成一個新的對象。並且,這兩種類的對象轉換十分容易。同時,如果要使用內容相同的字符串,不必每次都 new 一個 String。例如要在構造器中對一個名叫 s 的 String 引用變量進行初始化,把它設置爲初始值,應當這樣做:

public class Demo {
  private String s;
  ...
  s = "Initial Value";
  ...
}

而非s = new String("Initial Value");
後者每次都會調用構造器,生成新對象,性能低下且內存開銷大,並且沒有意義,因爲 String 對象不可改變,所以對於內容相同的字符串,只要一個 String 對象來表示就可以了。也就說,多次調用上面的構造器創建多個對象,他們的 String 類型屬性 s 都指向同一個對象。
上面的結論還基於這樣一個事實:
對於字符串常量,如果內容相同,Java 認爲它們代表同一個 String 對象。
而用關鍵字 new 調用構造器,總是會創建一個新的對象,無論內容是否相同。
至於爲什麼要把 String 類設計成不可變類,是它的用途決定的。其實不只 String,很多 Java 標準類庫中的類都是不可變的。在開發一個系統的時候,我們有時候也需要設計不可變類,來傳遞一組相關的值,這也是面向對象思想的體現。
不可變類有一些優點,比如因爲它的對象是隻讀的,所以多線程併發訪問也不會有任何問題。
當然也有一些缺點,比如每個不同的狀態都要一個對象來代表,可能會造成性能上的問題。所以 Java 標準類庫還提供了一個可變版本,即 StringBuffer。

五、判斷下面代碼的執行結果

String s1 = new String("abc");    
String s2 = "abc";
System.out.println(s1 == s2);   //false
System.out.println(s1.equals(s2));   //true

原因:s1記錄的是堆內存中對象的地址,s2記錄的是常量池中的地址

String s1 = "a" + "b" + "c";
String s2 = "abc";
System.out.println(s1 == s2);        //true    
System.out.println(s1.equals(s2));   //true    

原因:java中有常量優化機制,編譯時就把 “a” + “b” + "c"變成“abc”賦值給s1

String s1 = "ab";
String s2 = "abc";
String s3 = s1 + "c";
System.out.println(s3 == s2);            //false
System.out.println(s3.equals(s2));       //true

原因:因爲s1是一個變量,jvm運行的時候不認爲s3=“abc”,也就是無法使用常量池。因此s3會重新創建一個對象。

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