我只是想创建一个物体的浅层和深层的副本.我知道,在深度复制中,您使用要复制的对象的值创建一个新对象,以防止副作用.我注意到的一件事是,我的浅表复制不会产生副作用,但我不明白为什么.

public class Joo {
    public String name;
    
    public Joo(String a) {
        this.name = a; 
    }
    public Joo(Joo a) {
        this.name = a.name; 
    }
    
    public static void main(String[] args) {
        Joo a = new Joo("Bernt");
        Joo b = new Joo(a);
        
        System.out.println("a :" +a.name); //a :Bernt
        System.out.println("b :" +b.name); //b :Bernt

        b.name = "Ernie";
        System.out.println("a :" +a.name); //a :Bernt 
        System.out.println("b :" +b.name); //b :Ernie
    }
}

我预计当我更改b.name时,它也会更改a.name,因为b.name只是对a.name对象的引用,而不是真正的副本.

推荐答案

因为b.name只是a.name对象的参考,而不是真实的副本.

是的,这是真的,直到你写了b.name = "Ernie".这使得b.name引用了其他东西(即字符串"Ernie").=接线员就是这么做的.b.name不再是"a.name对象的引用".

因此,您需要以某种方式更改b.name,而不是引用其他内容.

然而,没有办法做到这一点.String is immutable.创建String之后,您无法调用任何方法或设置可更改String对象所代表的字符串的(公共)字段.另一方面,您可以将新对象指定给现有的String,就像您在这里所做的那样.

可以说,这是String不变的原因之一.浅复制String不会导致任何不想要的副作用,所以你实际上不需要深复制String.

要查看副作用,请使用可变类型,如StringBuilder:

public class Joo {
    public StringBuilder name;

    public Joo(String a) {
        this.name = new StringBuilder(a);
    }

    public Joo(Joo a) {
        this.name = a.name;
    }
}

不是指定一个StringBuilder的新实例,而是通过调用对象的方法之一来改变该对象:

b.name.append("Something");

现在它打印:

a :Bernt
b :Bernt
a :BerntSomething
b :BerntSomething

Java相关问答推荐

Spring安全实现多个SQL表身份验证

Java字符串常数池困惑

Java应用程序崩溃时试图读取联系人从电话

如何在Android上获取来电信息

XPages-在第二次点击按钮之前延迟

存根基类的受保护方法

使用REST客户端和对象映射器从字符串反序列化Json

无法使用ApacheSpark依赖项构建JavaFX应用程序

测试容器无法加载类路径初始化脚本

如何让JVM在SIGSEGV崩溃后快速退出?

有没有可能在时间范围内得到多种解决方案?

在Ubuntu 23.10上使用mp3创建JavaFX MediaPlayer时出错

根本不显示JavaFX阿拉伯字母

从Spring6中的JPMS模块读取类时出现问题

Spring Framework6.1中引入的新RestClient是否有适合于测试的变体,就像RestTemplate和TestRestTemplate一样?

深度优先搜索实现:算法只向右搜索

视图被推出线性布局-Android

我无法在我的Spring Boot应用程序中导入CSV依赖项

如何使用java区分以下结果

在java中使用SevenZip.openArchive方法后无法删除文件