Java String“常量”混乱

时间:2013-09-10 21:08:04

标签: java

我有点困惑,显然在这里遗漏了一些东西:

我读到java.lang.String的“是常量;它们的值在创建后无法更改。”

但如果我写下面的代码:

String line;
line = "Test1";
System.out.println(line);
line = "Test2";     
System.out.println(line);

终端输出:

Test1
Test2

看来我可以设置一个值,然后再为字符串设置另一个值。

如果我这样尝试没有区别:

String line2 = "Test3";
System.out.println(line2);
line2 = "Test4";
System.out.println(line2);

我仍然可以在最初设置之后设置该值。

我在哪里错了?

感谢。

5 个答案:

答案 0 :(得分:4)

字符串是不可变的,它们的值无法更改。那是真实的。

但是在您的代码中,您正在使用引用。

String line; //allocate variable
line = "Test1"; //assign to variable value "Test1"
System.out.println(line);
line = "Test2"; //assign to variable value "Test2"

你不能改变的是字符串本身而不是变量引用。

详情JLS 15.26

这适用于对象类型和原语。

答案 1 :(得分:3)

在JVM Test1和Test2中,在堆内存中创建了两个String值并分配了空间。你在做什么只是改变参考地址。这是代码语句的字节码。请关注ldc操作码,因为您可以看到lcd获得了不同的字符串引用。

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

  public static void main(java.lang.String[]);
    Code:
       0: ldc           #16                 // String Test1
       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: ldc           #30                 // String Test2
      12: astore_1
      13: getstatic     #18                 // Field java/lang/System.out:Ljava/io/PrintStream;
      16: aload_1
      17: invokevirtual #24                 // Method java/io/PrintStream.println:(Ljava/lang/String
;)V
      20: return
}

答案 2 :(得分:2)

参见评论

String line; // declares a variable of type String
line = "Test1";  // creates a new String object with value "Test1" and makes line reference it
System.out.println(line); // don't care
line = "Test2";  // creates a new String object with value "Test2" and makes line reference it

这是两个不同的对象。

改变它的价值就是做这样的事情

line = "Test1";
line[4] = "2";
System.out.println(line); // printing Test2

这在Java中是不可能的,因为String生成不可变实例。

分配引用和更改对象的值之间存在差异。

答案 3 :(得分:1)

字符串是不可变的。您无法更改String的值。 您可以创建一个新的String对象,也可以从String池中引用它。

String line;                   // line is at Location A
line = "Test1";               // Location A --> "Test1"
System.out.println(line);    // Prints Test1
line = "Test2";              // Location A --> "Test2" --> Reference to Test1 is lost
System.out.println(line);   // Prints Test2

答案 4 :(得分:1)

上面的所有答案都是正确的,String是不可变的,你不能编辑对象,另一方面你可以删除它们或编辑它们。

垃圾收集器将删除所有没有引用的对象,因为它们不能再使用了。

Java中有两个记忆:堆和堆栈。当变量存在于堆栈中时,对象存在于堆中。

创建时

String test1="Test1"

test1住在堆栈中,可以更改

然而,“Test1”生活不在Stack中,你无法编辑它。

String test1, test2;

test1 = test2 = "MyString"

如果更改test1 =“Hello”,test2将不受影响,也不会影响字符串本身。

Person person1, person2;
person1 = person2 = new Person("Nickname")

person1.rename("My new name");

另一方面,将编辑Person的名称(生活在堆中的对象)

它不需要更改Stack引用,person1和person2都会受到此更改的“影响”。