Java 为什么我的变量包含;2122“;而不是",;2322";?
这是一道考试题。幸运的是我选择了正确的答案,但我仍然不明白为什么它是正确的 考虑一下这个计划:Java 为什么我的变量包含;2122“;而不是",;2322";?,java,mutators,string-pool,Java,Mutators,String Pool,这是一道考试题。幸运的是我选择了正确的答案,但我仍然不明白为什么它是正确的 考虑一下这个计划: class D { protected C c; public D(C c) { this.c = new C(c); } public C getC() { return c; } public void setC(C c) { this.c = c; } } class C { protected String s; public C(S
class D {
protected C c;
public D(C c) {
this.c = new C(c);
}
public C getC() {
return c;
}
public void setC(C c) {
this.c = c;
}
}
class C {
protected String s;
public C(String s) {
this.s = s;
}
public C(C c) {
this(c.s);
}
public String getS() {
return s;
}
public void setS(String s) {
this.s = s;
}
public static void main(String[] args) {
C c1 = new C("1");
C c2 = new C("2");
D[] d = {
new D(c1), new D(c1), new D(c2), new D(c2)
};
d[0] = d[3];
c1.setS("3");
String r = "";
for (D i: d) {
r += i.getC().getS();
}
System.out.println(r);
}
}
它将打印2122
。但是,我希望2322
(运行代码时,我显然错了)。我的理由是:
在main方法的第三行中,D
的四个实例被初始化。
D
的构造函数创建了C
的一个新实例。C
的实例有一个String
变量,该变量指向内存中的某个点。现在,d[1]
中对象的实例变量c
,我们称之为c3
,有一个实例变量(typeString
),我们称之为s3
,指向与String s1
相同的内存,变量为c1
因此,当我们更改s1
时,我希望s3
的值也会更改,因为它指向内存中的同一点
另一方面,如果您更改D
的构造函数,请参见下文,您将得到2322
。我希望如此,因为现在d[1]
中的变量c3
直接指向c1
的内存位置
public D(C c) {
this.c = c;
}
到目前为止,我对解释的想法(可能是错误的):
s1
/s3
时,会生成新的String
对象(到目前为止,我假设它们指向String
池中的“1”
,因为C
的构造函数使其看起来是这样的)s1
时,它的指针将重定向到字符串
池中的“3”
。而不是池中的“1”
变成“3”
有人能解释这种行为吗?我的(错误的)推理中有哪些错误?这与
字符串
池无关。主要答覆:
这是因为D
基于C#C
创建了一个新的C
实例。这意味着D#c
的实例与构造函数D
中传递的参数c
的实例不同,因此修改该实例不会影响D#c
中的当前实例
你对这一切都解释得很好 以下是您正在测试的内容:
class Surprise {
String item;
public Surprise(String item) {
this.item = item;
}
//this is called copy constructor
//because you receive an object from the same class
//and copy the values of the fields into the current instance
//this way you can have a "copy" of the object sent as parameter
//and these two object references are not tied by any mean
public Surprise(Surprise another) {
//here you just copy the value of the object reference of another#item
//into this#item
this.item = another.item;
}
}
class Box {
Surprise surprise;
public Box(Surprise surprise) {
//here you create a totally new instance of Surprise
//that is not tied to the parameter surprise by any mean
this.surprise = new Surprise(surprise);
}
public static void main(String[] args) {
Surprise surprise1 = new Surprise("1");
Surprise surprise2 = new Surprise("2");
Box[] boxes = {
new Box(surprise1),
new Box(surprise1),
new Box(surprise2),
new Box(surprise2)
};
boxes[0] = boxes[3];
//you update surprise1 state
//but the state of Box#surprise in the boxes that used surprise1
//won't get affected because it is not the same object reference
surprise1.item = "3";
//print everything...
System.out.println("Boxes full of surprises");
//this code does the same as the printing above
for (Box box : boxes) {
System.out.print(box.surprise.item);
}
System.out.println();
}
}
可能是@njzk2的重复项。它不是重复项。但这有助于理解这个程序的结果。@LuiggiMendoza
因此,当我们更改s1时,我希望s3的值也会更改,因为它指向内存中的同一点。
对我来说,OP被java中传递和引用变量的方式弄糊涂了。@njzk2是的。而提供这种联系作为唯一的答案可能不足以解释这种行为。这就是为什么我提供了一个答案来详细解释这一点。首先感谢你的回答。我知道按值传递/引用的一般概念。如果构造函数意外地生成一个新字符串,即:This.item=new String(另一个.item),而不是重复使用“other”中的同一个字符串,那么这个示例对我来说是有意义的。我可以理解为什么会有不同的惊喜,但我很难理解为什么会有不同的字符串。@flisk,因为您只复制字符串引用的值。因此,然后更新shopprise1#item
,只影响该变量。同样的情况也可能发生在int
、Integer
甚至一个可变类上,因为您将shopprise1#item
与一个全新的引用相关联。啊,那么基本上,shopprise1#item会改变它的指针吗?也可以在中间驻留,put System.out.println(d[1].getC().getS()==c1.s);d[0]=d[3]之后的行。在这里你可以看到,字符串仍然是一样的(就在更改之前),因为它打印为true。好的,很好,我想我现在完全理解了。我用StringBuffer替换了所有字符串,并用这种方式更改了c1:c1.setS(c1.s.replace(0,1,3));这个项目达到了我的预期。因为StringBuffer是可变的,所以当它的值更改时,它不需要创建新实例(即更改指针)。这样它就印上了“2322”。谢谢@请注意,您正在修改状态。如果您使用c1.s=newstringbuffer(“3”)代码>然后将再次打印“2122”。同样,这是关于按值传递的。如果您使用new
关键字,那么对象是否是不可变的并不重要。