2011-04-29 61 views
16

以下Java代碼片段來自AP計算機科學實踐考試。Java字符串變量設置 - 引用還是值?

String s1 = "ab"; 
String s2 = s1; 
s1 = s1 + "c"; 
System.out.println(s1 + " " + s2); 

該代碼的輸出是BlueJ上的「abc ab」。但是,可能的答案選擇之一是「abc abc」。答案可能取決於Java是否設置了像基本類型(按值)或類似對象(通過引用)的字符串引用。

爲了進一步說明這一點,讓我們來看一個例子與基本類型:

int s1 = 1; 
int s2 = s1; // copies value, not reference 
s1 = 42; 

System.out.println(s1 + " " + s2); // prints "1 42" 

但是,說我們必須的BankAccount 對象持有餘額。

BankAccount b1 = new BankAccount(500); // 500 is initial balance parameter 
BankAccount b2 = b1; // reference to the same object 
b1.setBalance(0); 
System.out.println(b1.getBalance() + " " + s2.getBalance()); // prints "0 0" 

我不確定字符串是哪種情況。它們在技術上是對象,但是我的編譯器在將變量設置爲對方時似乎將它們視爲基本類型。

如果Java傳遞像原始類型這樣的字符串變量,答案是「abc ab」。但是,如果Java將字符串變量視爲引用任何其他對象,則答案將爲「abc abc」

您認爲哪個答案是正確的?

+0

你看過String的文檔嗎?它是說它是一個階級還是一個原始階級? – DJClayworth 2011-04-29 17:44:36

+0

您可能想要閱讀[javadoc](http://download.oracle.com/javase/6/docs/api/java/lang/String.html),因爲它可以回答您的問題。 – 2011-04-29 18:01:30

+4

'System.out.println(s1 +「」+ s2); //打印「1 42」'不是真的......它打印'「42 1」' – whytheq 2013-10-31 09:02:31

回答

27

java字符串是不可變的,所以你的重新分配實際上會導致你的變量指向一個新的String實例,而不是改變String的值。

String s1 = "ab"; 
String s2 = s1; 
s1 = s1 + "c"; 
System.out.println(s1 + " " + s2); 

on line 2,s1 == s2 AND s1.equals(s2)。在第3行連接之後,s1現在引用具有不變值「abc」的不同實例,所以s1 == s2和s1.equals(s2)都不會。

+1

它確實如此,但實際上並沒有回答OP更基本的問題。 – 2011-04-29 17:45:19

+5

當然可以。它隱含地解釋說他對String案件與BankAccount的比較是不一樣的。一個是分配一個新的實例,而另一個只是修改現有的實例。爲清楚起見,s1 = s1 +「c」基本上等於b = new StringBuilder(s1); b.append('c'); s1 = b.toString(); – Robin 2011-04-29 18:18:03

2

java.lang.String是一個對象,而不是一個基元。

的代碼在第一個例子中所做的是:

  1. 定義S1爲「AB」
  2. 集合S2等於相同的底層對象作爲S1
  3. 集合S1等於一個新的字符串,它是s1的舊值和「c」的組合

但是要回答有關參考或值的問題,請參考。

6

在Java中,String對象通過引用分配並傳遞給;這方面他們的表現完全像其他任何物體一樣。

然而,String s爲不變:有沒有那麼就地修改現有的字符串的值,而無需創建一個新的對象的操作。例如,這意味着s1 = s1 + "c"會創建一個新對象,並將存儲在s1中的引用替換爲對該新對象的引用。

9

String是否被視爲像原始對象或對象一樣是不相關的!

在字符串示例中,兩個字符串的串聯會生成一個新的字符串實例,然後將其分配給s1。變量s2仍然引用未改變的(!)舊的String實例。

假設的BankAccount必須設置平衡,它返回一個新的BankAccount的方法,你的例子看起來是這樣的:

BankAccount b1 = new BankAccount(500); // 500 is initial balance parameter 
BankAccount b2 = b1; // reference to the same object 
b1 = b1.createNewAccountWithBalance(0); // create and reference a new object 
System.out.println(b1.getBalance() + " " + b2.getBalance()); // prints "0 500" 
13

您的BankAccount和字符串之間的區別是,字符串是不變的。沒有'setValue()'或'setContent()'之類的東西。與您的銀行帳戶等效的例子是:

BankAccount b1 = new BankAccount(500); // 500 is initial balance parameter 
BankAccount b2 = b1; // reference to the same object 
b1 = new BankAccount(0); 
System.out.println(b1.getBalance() + " " + s2.getBalance()); // prints "0 500" 

所以,如果你認爲它是這樣的(實際上沒有編譯器做什麼,但功能上等同)的字符串連接的情況是:

String s1 = "ab"; 
String s2 = s1; 
s1 = new String("abc"); 
System.out.println(s1 + " " + s2); //prints "abc ab" 
9

的確,String是一個類,它是通過引用分配/傳遞的。 但是,什麼是令人困惑的是語句:

String s = "abc"; 

這表明字符串是primitve(如「int x = 10;」); 但這只是一條捷徑,聲明'String s =「abc」;'實際上編譯爲「String s = new String("abc");」 就像「Integer x = 10;」編譯爲「Integer x = new Integer(10);

這種機制被稱爲「拳擊」。

而更令人困惑的是:有一類「Integer」和原始「int」, 但字符串沒有原始當量(allthough char[]接近)

Sije德哈恩

0
int s1 = 1; 
int s2 = s1; // copies value, not reference 
s1 = 42; 

System.out.println(s1 + " " + s2); // prints "1 42" 

不打印"1 42""42 1"。考慮到每個離散行。首先s1分配1,然後s2分配s1,直到現在爲止1(假設java還沒有看到第三行)。然後java看到第三行並立即c把s1改爲42.然後java被告知打印到目前爲止所知道的信息,那就是s1是42,s2是1(舊的s1)。

至於字符串同樣的事情發生。

String s1 = "ab"; 
String s2 = s1; 
s1 = s1 + "c"; 
System.out.println(s1 + " " + s2);// prints "abc ab". 

堡字符串不一定改變S1而是現在S1是指一個新的String對象的堆內存,但舊的「AB」的對象仍然存在,與S2的一個新的參考!

0

斷言

如果Java的對待像任何其他對象引用字符串變量,答案是 「ABC ABC」

不正確。 Java確實將字符串變量視爲對任何其他對象的引用。 Strings是對象,但答案是「abc ab」。

問題不在於賦值操作符的作用。在您的示例中,賦值運算符在每種情況下都爲String對象分配一個引用。

問題是串聯運算符('+')的作用。它創建一個新的String對象。正如其他人所說,這是必要的,因爲一個String對象是不可變的,但它是一個操作符行爲的問題,而不僅僅是因爲String是不可變的。即使String對象是可變的,串聯運算符也可以返回一個新對象。

相比之下,在第二個示例中,b1.setBalance(0)不會創建新對象,它會修改現有對象。