關於建立String物件的抉擇

飄過的小熊發表於2016-09-07

關於建立String物件的抉擇

標籤(空格分隔): 與String有關的那些事兒
轉自部落格:java String 兩種不同的賦值 比較



我的舊記憶


之前我的大腦還是有概念的,只是比較模糊,我知道建立一個String物件有幾種形式。

  • String string=new String()
  • String string=”jfirehj”

但是我是真不知道這兩種形式有沒有區別,因此在比較String 物件的時候,理解到不了位。

public class EmptyTest {
    public static void main(String[] args) {
        String s1 = "iiii";
        String s2 = "iiii";
        if(s1==s2){
            System.out.println("you are right");
        }
        if (s1.equals(s2)) {
            System.out.println("you are right again");

        }
    }
}

輸出是

you are right
you are right again

再來一次

public class EmptyTest {
    public static void main(String[] args) {
        String s1 = new String("iiii");
        String s2 = new String("iiii");
        if (s1 == s2) {
            System.out.println("you are right");
        }
        if (s1.equals(s2)) {
            System.out.println("you are right again");

        }
    }
}

輸出:

you are right again

使用new是在堆上建立了兩個不同的物件。但是這個字串建立的怎麼來進行解釋呢?


新的認識


找到的兩篇寫得比較好的博文:
第一篇
第二篇

原來就還有一個常量池的概念。

類似普通物件,通過new 建立字串物件


String str = new String(“Hello”); 記憶體圖如下圖所示,系統會先建立一個匿名物件”Hello”存入堆記憶體(我們暫且叫它A),然後new關鍵字會在堆記憶體中又開闢一塊新的空間,然後把”Hello”存進去,並且把地址返回給棧記憶體中的str, 此時A物件成為了一個垃圾物件,因為它沒有被任何棧中的變數指向,會被GC自動回收
此處輸入圖片的描述

直接賦值

如String str = “Hello”; 首先會去緩衝池中找有沒有一個”Hello”物件,如果沒有,則新建一個,並且入池,所以此種賦值有一個好處,下次如果還有String物件也用直接賦值方式定義為“Hello”, 則不需要開闢新的堆空間,而仍然指向這個池中的”Hello”,原來如此
此處輸入圖片的描述

這段程式碼證明結論:
此處輸入圖片的描述

手動入池

即使使用new關鍵字,第一種方式賦值,也可以使用一個java中的手動入池指令,讓所建立的物件入池,以後依然可以背重複使用,利用下面兩段程式碼可以測試, 如下圖,結果顯然是false,因為二者的地址不同。

此處輸入圖片的描述

國際慣例:總結

通過常量池的形式可以很好的提高效率,因此提倡直接賦值

後話:為什麼String 可以直接賦值

開啟了String.class,有這麼一段介紹:

/** 
* The <code>String</code> class represents character strings. All 
 * string literals in Java programs, such as <code>"abc"</code>, are 
 * implemented as instances of this class. 
 * <p> 
 * Strings are constant; their values cannot be changed after they 
 * are created. String buffers support mutable strings. 
 * Because String objects are immutable they can be shared. For example: 
 * <p><blockquote><pre> 
 *     String str = "abc"; 
 * </pre></blockquote><p> 
 * is equivalent to: 
 * <p><blockquote><pre> 
 *     char data[] = {'a', 'b', 'c'}; 
 *     String str = new String(data); 
 * </pre></blockquote><p> 
 * Here are some more examples of how strings can be used: 
 * <p><blockquote><pre> 
 *     System.out.println("abc"); 
 *     String cde = "cde"; 
 *     System.out.println("abc" + cde); 
 *     String c = "abc".substring(2,3); 
 *     String d = cde.substring(1, 2); 
 * </pre></blockquote> 
 * <p> 
 */  

通過上面的介紹,我們可以清楚,直接賦值的話,是通過編譯器在起作用,當你對”abc”沒有通過new建立時,他會自動預設給你呼叫建構函式new String(char value[]). 不顯式呼叫String的建構函式(通過new叫顯式呼叫),其實JDK編譯器會自動給你加上。

編譯器主動呼叫構造方法的情況出現很多次了也

相關文章