2013-04-02 126 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