在Java中,引用拷贝、浅拷贝和深拷贝的概念可以通过以下代码案例来说明:
引用拷贝(直接赋值)
案例:
public class Main {
public static void main(String[] args) {
// 创建一个Person对象
Person original = new Person("Alice", 25);
// 引用拷贝:直接将对象引用赋值给新的引用
Person referenceCopy = original;
// 修改原始对象的属性
original.setName("Bob");
// 输出结果
System.out.println(original.getName()); // Bob
System.out.println(referenceCopy.getName()); // Bob (因为两个引用指向同一个对象)
}
}
class Person {
private String name;
private int age;
public Person(String name, int age) {
this.name = name;
this.age = age;
}
public void setName(String name) {
this.name = name;
}
public String getName() {
return name;
}
// ... 其他getter和setter
}
在这个例子中,referenceCopy
是 original
的引用拷贝,它们指向相同的内存地址,因此当原始对象的属性发生改变时,通过引用拷贝得到的对象也会反映出这些变化。
浅拷贝
案例:
import java.util.Date;
public class Main {
public static void main(String[] args) {
// 创建一个包含嵌套对象的Person对象
PersonWithAddress original = new PersonWithAddress("Alice", 25, new Address("1st Street"));
// 浅拷贝:使用Cloneable接口实现浅拷贝
PersonWithAddress shallowCopy = original.clone();
// 修改原始对象内嵌对象的属性
original.getAddress().setStreet("2nd Street");
// 输出结果
System.out.println(original.getAddress().getStreet()); // 2nd Street
System.out.println(shallowCopy.getAddress().getStreet()); // 2nd Street (因为地址对象被共享)
}
}
class PersonWithAddress implements Cloneable {
private String name;
private int age;
private Address address;
public PersonWithAddress(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone(); // 这里进行的是浅拷贝
}
// ... getter和setter
public Address getAddress() {
return address;
}
}
class Address {
private String street;
public Address(String street) {
this.street = street;
}
public void setStreet(String street) {
this.street = street;
}
public String getStreet() {
return street;
}
}
在这个案例中,PersonWithAddress
类实现了 Cloneable
接口并调用了 super.clone()
方法来进行浅拷贝。虽然 shallowCopy
创建了一个新的 PersonWithAddress
对象,但其中的 address
属性仍然与 original
中的 address
引用相同,这意味着它们共享同一个内嵌的 Address
对象。因此,即使进行了浅拷贝,修改原始对象内嵌对象的属性仍会影响到拷贝后的对象。
深拷贝
案例:
import java.util.Date;
import java.io.Serializable;
public class Main {
public static void main(String[] args) {
// 创建一个包含嵌套对象的Person对象
PersonWithSerializableAddress original = new PersonWithSerializableAddress("Alice", 25, new SerializableAddress("1st Street"));
// 深拷贝:使用序列化和反序列化实现深拷贝
try {
ByteArrayOutputStream baos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(baos);
oos.writeObject(original);
ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
PersonWithSerializableAddress deepCopy = (PersonWithSerializableAddress) ois.readObject();
// 修改原始对象内嵌对象的属性
original.getAddress().setStreet("2nd Street");
// 输出结果
System.out.println(original.getAddress().getStreet()); // 2nd Street
System.out.println(deepCopy.getAddress().getStreet()); // 1st Street (因为深拷贝后地址对象不共享)
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
}
}
class PersonWithSerializableAddress {
private String name;
private int age;
private SerializableAddress address;
// 构造函数、getter和setter...
public SerializableAddress getAddress() {
return address;
}
}
class SerializableAddress implements Serializable {
private String street;
public SerializableAddress(String street) {
this.street = street;
}
public void setStreet(String street) {
this.street = street;
}
public String getStreet() {
return street;
}
}
在这个深拷贝的例子中,我们利用了Java的序列化和反序列化机制。通过将对象写入字节流再从字节流读取,可以实现深拷贝,确保所有嵌套的对象也都会被复制一份新的实例。因此,即使修改了原始对象内嵌对象的属性,也不会影响到深拷贝后的对象。
注意:实际开发中,如果要实现深拷贝,通常会重写 clone()
方法,并在其中手动处理嵌套对象的深拷贝,而不是简单地调用 super.clone()
。另外,对于复杂的数据结构,可能需要设计更复杂的深拷贝逻辑,尤其是涉及循环引用或非序列化对象时。上述深拷贝的例子简化了许多细节,真实情况可能需要更多异常处理和其他策略。