2013-04-02 127 views
6

我和我的朋友在討論串上,我們被困在這:多少個String對象..?

String str = "ObjectOne"+"ObjectTwo"; 

他說,共有三個對象將被創建和我說一個對象將被創建。

他背後的3個對象的邏輯是:一個用於「ObjectOne」,另一個用於「ObjectTwo」,第三個是兩個String對象的連接版本。

我後面一個對象的邏輯是在編譯的時候了字符串對象將在字節碼聯接爲:

String str = "ObjectOneObjectTwo"; 

,並在運行時只有一個對象會以這樣的方式來創建。這背後的真相是什麼?

+0

有類似的問題在這裏:http://stackoverflow.com/questions/15669067/fastest-way-of-converting-integer-to-string-in-java – msi

回答

11

如果你寫(文字或常量)

String str = "ObjectOne"+"ObjectTwo"; 

這相當於

String str = "ObjectOneObjectTwo"; // compiler optimize it so one Object 
7

您可以通過使用javap工具拆卸代碼中找到了這一點爲自己,看什麼編譯器製成的。假設你有這樣的例子:

public class Example { 
    public static void main(String[] args) { 
     String s = "ObjectOne" + "ObjectTwo"; 
     System.out.println(s); 
    } 
} 

編譯它,然後用javap -c Example拆卸。其結果是:

Compiled from "Example.java" 
public class Example { 
    public Example(); 
    Code: 
     0: aload_0 
     1: invokespecial #1     // Method java/lang/Object."<init>":()V 
     4: return 

    public static void main(java.lang.String[]); 
    Code: 
     0: ldc   #2     // String ObjectOneObjectTwo 
     2: astore_1 
     3: getstatic  #3     // Field java/lang/System.out:Ljava/io/PrintStream; 
     6: aload_1 
     7: invokevirtual #4     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     10: return 
} 

正如你看到的,只有一個String對象,其中包含「ObjectOneObjectTwo」。所以,實際上,編譯器會在編譯時爲你編譯連接。

+0

+1爲你自我解釋的例子。 – Sajmon

-3
String str = "ObjectOne"+"ObjectTwo"; 

3個對象將被創建爲

1- 「ObjectOne」

2- 「ObjectTwo」

3- 「ObjectOneObjectTwo」

使用

StringBuffer tmp = new StringBuffer("ObjectOne"); 
tmp.append("ObjectTwo"); 
str = tmp.toString(); 
+0

hai請在投票前搜索您的字符串連接概念down.http://javapapers.com/core-java/java-string-concatenation/ –

+1

'String fruit =「Apple」;水果=水果+「世界」;'這確實會創造兩個對象。但是'String fruit =「Apple」+「World」;'只會創建一個對象。 OP在詢問第二種語法。 – AmitG

1

您可以輕鬆地這樣檢查自己:

  1. 編譯下面的程序:

    public static void main(String[] args) { 
        String str = "ObjectOne"+"ObjectTwo"; 
        System.out.println(str); 
    } 
    
  2. 檢查由編譯器發出的字節碼:

    javap.exe -v Test.class 
    

爲主要方法,這打印:

public static void main(java.lang.String[]); 
    flags: ACC_PUBLIC, ACC_STATIC 

    Code: 
     stack=2, locals=2, args_size=1 
     0: ldc   #16     // String ObjectOneObjectTwo 
     2: astore_1  
     3: getstatic  #18     // Field java/lang/System.out:Ljava/io/PrintStream; 
     6: aload_1  
     7: invokevirtual #24     // Method java/io/PrintStream.println:(Ljava/lang/String;)V 
     10: return   
     LineNumberTable: 
     line 6: 0 
     line 7: 3 
     line 8: 10 
     LocalVariableTable: 
     Start Length Slot Name Signature 
       0  11  0 args [Ljava/lang/String; 
       3  8  1 str Ljava/lang/String; 
} 

正如您所看到的,程序使用ldc字節碼指令來引用已加載的單個字符串實例(當Test.class被加載時)。因此在執行該行期間不會創建新對象。

編譯器是由required Java語言規範來執行此優化:

String對象是新創建(§12.5),除非表達是一個編譯時間常量表達式(§15.28)。

0
String str1 = "ObjectOne"; 
String str2 = "ObjectTwo"; 
str1 = str1+str2; 

在上述情況下,三個對象將被創建。

但是,當你這樣定義

String str = "ObjectOne"+"ObjectTwo"; 

那麼只有一個對象將被創建。編譯器優化它。

0

字符串對象是不可變的。

String str = "ObjectOne"+"ObjectTwo"; 

     is same as 

    String str = "ObjectOneObjectTwo"; 

通過不可變,我們的意思是存儲在String對象中的值不能被改變。接下來的問題就是「如果String是不可變的,那麼我怎麼能夠隨時改變對象的內容?」。那麼,確切地說,它不是反映你所做的更改的相同的String對象。在內部創建一個新的String對象來執行更改。

因此,假設你聲明一個String對象:

String myString = "Hello"; 

接下來,您要追加「來賓」,以相同的字符串。你是做什麼?

myString = myString + " Guest"; 

當您打印myString的內容時,輸出將爲「Hello Guest」。儘管我們使用了相同的對象(myString),但在內部創建了一個新對象。所以mystring會引用「Hello Guest」。對hello的引用會丟失。

String s1 = "hello"; //case 1 
    String s2 = "hello"; //case 2 

在情況1中,文字s1是新創建並保存在池中。但在情況2中,文字s2引用s1,它不會創建新的。

if(s1 == s2)System.out.println(「equal」); //輸出等於

 String s= "abc"; //initaly s refers to abc 
     String s2 =s; //s2 also refers to abc 
     s=s.concat("def"); // s refers to abcdef. s no longer refers to abc. 

enter image description here