java - 为什么我的变量包含 "2122"而不是 "2322"?

标签 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(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)有一个实例变量(类型为 String ),我们称之为s3,指向与String s1相同的内存,变量c1

因此,当我们更改 s1 时,我预计 s3 的值也会更改,因为它指向内存中的同一位置。

顺便说一句,如果您更改 D 的构造函数(请参见下文),您将得到 2322。正如我所料,因为现在 d[1] 中的变量 c3 直接指向 c1 的内存位置。

public D(C c) {
  this.c = c;
}

到目前为止我对解释的想法(可能是错误的):

  1. 初始化实例变量 s1/s3 时,会创建新的 String 对象(到目前为止,我假设它们指向 “1”String 池中,因为 C 的构造函数使它看起来像这样)
  2. 更改s1时,其指针将重定向到String池中的“3”。而不是“1”在池中变成“3”

有人能解释一下这种行为吗?我的(错误的)推理有哪些错误?

最佳答案

这与String池根本无关。主要回答:Is Java "pass-by-reference" or "pass-by-value"?

这是因为 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();
    }
}

关于java - 为什么我的变量包含 "2122"而不是 "2322"?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/25389506/

相关文章:

Java Mutator : initialize vs. 传递给参数

c++ - 在类中改变私有(private) vector 的最佳方法

java - 带有 println 的池中的字符串计数

Java SE 字符串池

java - LWJGL2 多灯不亮?所有实体都是黑色的

java - 无法使用 pom.xml 中的 Tycho 1.0.0 解析 "eclipse-plugin"打包类型

swift - 正确应用封装

java - 创建并有机会从字符串池中创建 String 对象有什么意义

java - Java中的谓词

java - 使用 Java 计算 11^-1 mod 26