Java字符串变量设置 - 引用还是值?

时间:2011-04-29 17:39:14

标签: java string variables reference

以下Java代码段来自AP计算机科学实践考试。

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

此代码的输出是BlueJ上的“abc ab”。但是,其中一个可能的答案选择是“abc abc”。答案可以取决于Java是否将String引用设置为基本类型(按值)或类似对象(通过引用)。

为了进一步说明这一点,让我们看一下原始类型的例子:

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"

我不确定Strings的情况如何。它们在技术上是对象,但我的编译器似乎在将变量设置为彼此时将它们视为原始类型。

如果Java传递String变量(如原始类型),答案是“abc ab”。但是,如果Java将String变量视为对任何其他Object的引用,则答案为“abc abc”

您认为哪个是正确答案?

9 个答案:

答案 0 :(得分:27)

java字符串是不可变的,因此您的重新分配实际上会导致您的变量指向String的新实例,而不是更改String的值。

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

在第2行,s1 == s2 AND s1.equals(s2)。在第3行连接之后,s1现在引用一个具有不可变值“abc”的不同实例,因此s1 == s2和s1.equals(s2)都不是。

答案 1 :(得分:13)

您的BankAccount和String之间的区别在于String是不可变的。没有'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"

答案 2 :(得分:10)

将String视为基元还是像对象一样无关紧要!

在String示例中,两个字符串的串联产生一个新的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"

答案 3 :(得分:10)

确实,String是一个类,它是通过引用分配/传递的。 但令人困惑的是声明:

String s = "abc";

这表明String是一个原始的(如'int x = 10;'); 但这只是一个捷径,声明'String s =“abc”;'实际编译为“String s = new String( "abc" );” 就像“Integer x = 10;”编译为“Integer x = new Integer( 10 );

一样

这种机制被称为'拳击'。

更令人困惑的是:有一个班级“Integer”和一个原始的“int”, 但String没有原始的等价物(尽管char[]接近)

Sije de Haan

答案 4 :(得分:7)

在Java中,String个对象被分配并通过引用传递;在这方面,他们的行为与任何其他对象完全一样。

但是,String不可变的:没有一个操作可以修改现有字符串的值,而不创建新对象。例如,这意味着s1 = s1 + "c"创建了一个新对象,并将s1中存储的引用替换为对此新对象的引用。

答案 5 :(得分:4)

String 是一个类,因此String变量 是一个引用。但它是一种内在的语言,因为Java具有特殊的处理和语法,这就是为什么你可以像你的例子那样做的事情。

参见例如http://download.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html

答案 6 :(得分:3)

java.lang.String是一个对象,而不是一个原语。

第一个例子中的代码是:

  1. 将s1定义为“ab”
  2. 将s2设置为与s1
  3. 相同的基础对象
  4. 将s1设为等于新字符串,该字符串是s1旧值和“c”的组合
  5. 但要回答你关于参考或价值的问题,可以参考。

答案 7 :(得分:1)

断言

  

如果Java将String变量视为对任何其他Object的引用,则答案为" abc abc"

不正确。 Java确实将String变量视为对任何其他Object的引用。 Strings是对象,但答案是" abc ab"尽管如此。

问题不在于赋值运算符的作用。赋值运算符在示例中的每种情况下都会为String对象分配一个引用。

问题在于串联运算符(' +')的作用。它创建一个新的String对象。正如其他人所说,这是必要的,因为String对象是不可变的,但它是操作符行为的问题,而不仅仅是因为String是不可变的。即使String对象是可变的,连接运算符也可以返回一个新的对象。

相比之下,在第二个示例中,b1.setBalance(0)不会创建新对象,它会修改现有对象。

答案 8 :(得分: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看到第三行并立即将s1更改为42.之后,java被告知打印到目前为止它知道的内容,那就是s1是42而s2是1(旧的s1)。

对于String,同样的事情发生了。

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

Fort String它不一定会改变s1,而是s1现在引用堆内存中的一个新的String对象,但旧的“ab”对象仍然存在,并带有s2的新引用!