以下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”
您认为哪个是正确答案?
答案 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是一个对象,而不是一个原语。
第一个例子中的代码是:
但要回答你关于参考或价值的问题,可以参考。
答案 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的新引用!