2011-04-29 77 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)不会创建新对象,它会修改现有对象。