Java字符串变量设置-参考还是值?

问题描述

| 以下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\"
我不确定字符串是哪种情况。从技术上讲,它们是对象,但是当相互设置变量时,我的编译器似乎将它们视为原始类型。 如果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和字符串之间的区别在于字符串是不可变的。没有\'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\"
    ,将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没有与之等效的原语(尽管
char[]
接近) 西耶·德·汉     ,在Java中,“ 15”个对象是通过引用分配和传递的。在这方面,它们的行为与其他任何对象完全相同。 但是,ѭ15是不可变的:没有一个操作可以修改现有字符串的值,而无需创建新对象。例如,这意味着
s1 = s1 + \"c\"
创建一个新对象,并用对此新对象的引用替换
s1
中存储的引用。     ,
String
是一个类,因此a15ѭ变量是一个引用。但这是一种语言固有的语言,就Java而言,Java具有特殊的处理和语法,这就是为什么您可以做类似示例的事情。 参见例如http://download.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.html。     ,java.lang.String是一个对象,而不是基元。 该代码在第一个示例中所做的是: 将s1定义为\“ ab \” 将s2设置为与s1相同的基础对象 将s1设置为等于s1的旧值和\“ c \”的新字符串 但是要回答有关参考或价值的问题,请参考。     ,断言   如果Java将String变量视为对任何其他Object的引用一样,则答案为\“ abc abc \” 是不正确的。 Java确实将String变量视为对任何其他Object的引用。字符串是对象,但答案仍然是“ abc ab”。 问题不在于赋值运算符做什么。在您的示例中,赋值运算符都会为String对象分配一个引用。 问题是串联运算符(\'+ \')的作用。它创建一个新的String对象。正如其他人所说,这是必需的,因为String对象是不可变的,但这是操作员行为的问题,而不仅仅是因为String是不可变的。即使String对象是可变的,连接运算符也可以返回新的Object。 相反,在第二个示例中,b1.setBalance(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,到目前为止,s1一直为1(假设java尚未看到第三行。)然后java看到了第三行,立即将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\".
Fort String并不一定更改s1,而是s1现在引用了堆内存中的新String对象,但是旧的“ ab \”对象仍然存在,并带有新引用s2!     

相关问答

依赖报错 idea导入项目后依赖报错,解决方案:https://blog....
错误1:代码生成器依赖和mybatis依赖冲突 启动项目时报错如下...
错误1:gradle项目控制台输出为乱码 # 解决方案:https://bl...
错误还原:在查询的过程中,传入的workType为0时,该条件不起...
报错如下,gcc版本太低 ^ server.c:5346:31: 错误:‘struct...