2013-09-10 58 views
1

我略有困惑,顯然失去了一些東西: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); 

我仍然可以對其進行了初始設置後,設置的值。

我在哪裏出錯了?

謝謝。

+8

在你的例子中,你沒有修改這個值,你正在修改這個參考。 –

+0

http://en.wikipedia.org/wiki/Immutable_object – Habib

+0

感謝所有回覆,一切有用。非常認識到參考是什麼變化。這僅僅是針對某些對象還是它也適用於基元類型? – Xerphiel

回答

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產生不變的情況下。

分配引用和更改對象的值有所不同。

+0

謝謝你的信息。這隻適用於基於對象的變量,那麼基元類型呢? – Xerphiel

+0

@Xerphiel關於基元的事情是它們是編程語言的原子(夸克)。你不能再打破它們,所以談論改變它們的價值是沒有意義的。一個對象可以由多個原始字段和其他引用字段組成。你可以改變其中的任何一個,從而改變對象的值。 –

3

在JVM Test1和Test2中,有兩個字符串值被創建並在堆內存中分配空間。你在做什麼只是改變參考地址。這是你的代碼語句的字節碼。請僅關注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 
} 
+0

我喜歡你要進入的細節,但我不太明白100%。你能詳細說明ldc嗎? 謝謝。 – Xerphiel

+0

通過用幾句話來解釋JVM的工作原理,我不太容易理解。請閱讀這篇文章http://www.ibm.com/developerworks/ibm/library/it-haggar_bytecode/之後,你可以問任何你想要的。 –

+0

ldc將一個單字常量壓入操作數堆棧。 ldc採用單個參數,這是要推送的值。下面的Java類型可以使用LDC推: INT 浮動 字符串 –

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

這適用於對象類型和原始。

+0

謝謝,這隻適用於基於對象的變量,那麼基元類型呢? – Xerphiel

1

字符串是不可變的。您不能更改字符串的值。 您可以創建一個新的字符串對象或從字符串池中引用它。上述

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 
1

所有答案都是正確的,字符串是不可變的,你不能編輯對象,在另一方面,引用你可以將其刪除或編輯。

垃圾收集器將刪除所有沒有引用的對象,因爲它們不能再被使用。

Java中有2個存儲器:堆和堆棧。當變量存在於堆棧中時,該對象位於堆中。

當您創建

String test1="Test1" 

test1的是生活在THES堆棧,並且可以更改

但是「Test1的」住不在堆棧,你不能編輯它。

String test1, test2; 

test1 = test2 = "MyString" 

如果您更改test1 =「Hello」,則test2不會受到影響,也不會影響字符串本身。

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

person1.rename("My new name"); 
在另一方面

這裏將編輯的人的姓名(即住在堆對象)

它並不需要改變棧參考,並都PERSON1和PERSON2將會受到這種變化的「影響」。