在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()); // BobSystem.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 StreetSystem.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;}@Overrideprotected Object clone() throws CloneNotSupportedException {return super.clone(); // 这里进行的是浅拷贝}// ... getter和setterpublic 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 StreetSystem.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()
。另外,对于复杂的数据结构,可能需要设计更复杂的深拷贝逻辑,尤其是涉及循环引用或非序列化对象时。上述深拷贝的例子简化了许多细节,真实情况可能需要更多异常处理和其他策略。