本文共 4311 字,大约阅读时间需要 14 分钟。
在Java编程中,深拷贝和浅拷贝是非常重要的概念,了解它们的区别和实现方式,可以帮助我们更好地理解Java对象的传递机制。以下是关于浅拷贝和深拷贝的详细解释。
这是最常用的方式,通过调用类的构造方法创建对象。
Object obj = new Object();
调用类的无参构造方法创建对象。
Person p2 = (Person) Class.forName("com.ys.test.Person").newInstance();
通过反射调用指定的构造方法创建对象。
Person p3 = (Person) Person.class.getConstructors()[0].newInstance();
通过对象的 clone() 方法创建内容相同的对象。
Person p4 = (Person) p3.clone();
将对象序列化为字节流,然后反序列化为新对象。
// 深度拷贝Object deepCopy = new Object() { @Override public Object clone() throws CloneNotSupportedException { return super.clone(); }};
protected native Object clone() throws CloneNotSupportedException;
这是一个 native 方法,由Java虚拟机实现,用于创建对象的浅拷贝。
@Testpublic void testShallowClone() throws Exception { Person p1 = new Person("zhangsan", 21); p1.setAddress("湖北省", "武汉市"); Person p2 = (Person) p1.clone(); System.out.println("p1: " + p1); System.out.println("p2: " + p2); p2.setAddress("湖北省", "荆州市"); System.out.println("p1地址变化: " + p1.getAddress());}
输出结果显示,修改 p2 的地址后,p1 的地址也随之改变,这是浅拷贝的特点。
char
, boolean
, byte
, short
, int
, long
, float
, double
。String c = new String("abc");String d = c;// c 和 d 引用同一个 String 对象。
public class Person implements Cloneable { private String pname; private int page; private Address address; public Person(String pname, int page) { this.pname = pname; this.page = page; this.address = new Address(); } @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }}
Person p1 = new Person("zhangsan", 21);p1.setAddress("湖北省", "武汉市");Person p2 = p1.clone();// p2 的 address 引用与 p1 的 address 引用相同。
确保每个对象的所有引用对象也复制到新对象中,形成完全独立的对象。
public class Address implements Cloneable { private String provices; private String city; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); }}
public Object deepClone() throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject();}
@Testpublic void testDeepClone() throws Exception { Person p1 = new Person("zhangsan", 21); p1.setAddress(new Address("湖北省", "武汉市")); Person p2 = p1.deepClone(); System.out.println("p1地址: " + p1.getAddress()); System.out.println("p2地址: " + p2.getAddress());}
输出结果显示,p1 和 p2 的地址不同,说明深拷贝成功。
重写每个引用类型的 clone 方法,确保深拷贝。
public class Address implements Cloneable { @Override protected Object clone() throws CloneNotSupportedException { Address addressClone = (Address) super.clone(); addressClone.provinces = new String(addressClone.provinces); addressClone.city = new String(addressClone.city); return addressClone; }}
确保所有字段都被序列化。
public class Person implements Serializable { private String pname; private int page; private Address address; private static final long serialVersionUID = 1234567890L; public Person(String pname, int page) { this.pname = pname; this.page = page; this.address = new Address(); } public Object deepClone() throws Exception { ByteArrayOutputStream bos = new ByteArrayOutputStream(); ObjectOutputStream oos = new ObjectOutputStream(bos); oos.writeObject(this); ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray()); ObjectInputStream ois = new ObjectInputStream(bis); return ois.readObject(); }}
使用工具如 Apache Commons 的 BeanUtils 或 Google Guava 的 Objects 类进行深拷贝。
理解这两种拷贝方式,能够帮助开发者在设计和维护Java程序时,正确选择适用的拷贝策略,提升程序的稳定性和可维护性。
转载地址:http://pngl.baihongyu.com/