你們好,我是Java最全面試題庫
的提褲姐,本篇文章是面試系列文章的第五篇,主要介紹了JavaSE中String相關的面試題,在以後會順着開篇的思惟導圖一直總結下去,作到日更!若是我能作到百日百更
,但願你也能夠跟着百日百刷
,一百天養成一個好習慣。java
不一樣,內存分配的方式不一樣。String str="aaa"
,建立了1個對象,建立的"aaa"是常量,jvm將其分配在常量池中;String str=new String("aaa")
,建立了2個對象,一個是在常量池中,一個在堆內存中。面試
一共有2個引用,3個對象;
"aa"與"bb"都是常量,常量的值不能改變,當執行字符串拼接的時候,會建立一個新的常量"aabb",將其存到常量池中。安全
沒有。
由於 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記錄的是常量池中的地址jvm
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會從新建立一個對象。優化