Java String变量设置 – 引用还是值?

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

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" 

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

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

您认为哪个是正确的答案?

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)都不是。

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" 

因此,如果您以这种方式考虑它(实际上不是编译器所做的,但在function上等效),字符串连接方案是:

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

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" 

实际上,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没有原始的等价物(allthough char[]接近)

Sije de Haan

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

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

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

请参阅http://download.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html 。

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

代码在第一个例子中做了什么:

  1. 将s1定义为“ab”
  2. 将s2设置为与s1相同的基础对象
  3. 将s1设置为等于s1的旧值和“c”的组合的新字符串

但要回答你关于参考或价值的问题,可以参考。

 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的新引用!

断言

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

是不正确的。 Java确实将String变量视为对任何其他Object的引用。 字符串是对象,但答案是“abc ab”。

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

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

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