【发布时间】:2025-11-21 22:30:01
【问题描述】:
这几天我在学习Java的clone方法。我了解到clone 使用浅拷贝。如果我想实现一个对象的深拷贝,那么我应该遵循this website中的以下原则
无需单独复制原语。 原类中的所有成员类都应支持克隆,并且在上下文中原类的clone方法中应在所有成员类上调用super.clone()。
在我的理解中,String在Java中是一种引用,为了更好的表达我的观点,代码如下:
// User.java
public class User implements Cloneable{
private String name;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
// Getter() ,setter() and toString() are omitted here
}
以下代码为测试代码:
User user = new User();
user.setName("one");
User clone = (User)user.clone();
clone.setName("two");
System.out.println(user.getName()); // I think it should print "two", but actually "one"
所以在我的示例中,我似乎创建了User 的深层副本(是吗?)
以下是我对Java内存的理解:
①表示我创建一个副本,②是字符串的变化。
所以如果我的图片是正确的,它应该打印“二”,对吧?
我知道java中的String是不可变的的,我想这大概就是为什么会出现这种情况的原因,但是我不知道这是怎么发生的,为什么会发生这种情况。 p>
根据@Jesper 的图片,我新建一张图片来更具体地解释我的问题。
还有演示代码:
public class Employee implements Cloneable {
private int employeeId;
private String employeeName;
private Department department;
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // shallow copy
}
// Getter() ,setter() and toString() are omitted here
}
public class Department{
private int id;
private String name;
// Getter() ,setter() and toString() are omitted here
}
测试代码:
Department hr = new Department(1, "Human Resource");
Employee original = new Employee(1, "Admin", hr);
Employee cloned = (Employee) original.clone();
cloned.getDepartment().setName("Finance");
System.out.println(original.getDepartment().getName()); //print Finance
还有图片:
红色部分是关键。如果是java.lang.String 对象,它将创建一个新对象(如上所示从“一”到“二”),但如果是另一个类对象(这里是Department 类),那么似乎会有只有一个对象(而不是创建一个),所以我的问题是为什么字符串在深拷贝和浅拷贝中是 special 的?这与String 不变性有关吗?
提前致谢!
【问题讨论】:
-
不,你有两个独立的用户对象。浅拷贝仍然是拷贝,不是同一个对象。设置一个字段不会改变另一个字段。这适用于任何字段,而不仅仅是字符串。
-
@khelwood 我编辑了我的问题。而在示例 2(员工和部门)中,代码
System.out.println(original.getDepartment() == cloned.getDepartment());将打印true,这意味着原始和克隆共享同一个对象。 -
关于您的添加:不,字符串没有什么特别之处。您之前的代码和第二个示例之间的区别:您没有更改克隆的
Employee对象中的部门;你要更深一层,你改变Department对象中的name。如果您会使用cloned.setDepartment(new Department(...));而不是cloned.getDepartment().setName(...);,那么它将与您的第一个示例相同。 -
"表示原始和克隆共享同一个对象。"——表示原始和克隆中的
deparment字段都指向同一个部门对象,因为您没有复制Department。但是如果你将一个员工的department设置为另一个Department对象,它不会影响到另一个员工,因为它们是不同的对象。与第一个示例中的字符串相同。 -
我知道我哪里出错了:我进入了更深的层次,这让我很困惑!非常感谢!
标签: java string deep-copy shallow-copy