Java的深拷贝和浅拷贝都是用于复制对象的常用方式。在进行对象复制时,我们需要了解两者的区别,根据具体需求选择合适的方式进行对象复制。
什么是浅拷贝?
浅拷贝是指直接复制对象,复制后的对象和原对象共享同一块内存空间(即,原对象和复制后对象都指向同一块内存空间)。如果对象存在引用类型属性,复制后的对象和原对象的引用类型属性指向同一个对象。如果其中一个对象对引用类型属性进行修改,另一个对象也会受到影响。
浅拷贝的三种实现方式
- 重写Object类的clone()方法
Java中的所有类都继承自Object类,该类中定义了一个clone()方法,用于创建一个新对象的副本。在使用该方法时,需要注意以下几点:
- 类实现Cloneable接口,否则在调用clone方法时会抛出CloneNotSupportedException异常。
- clone()方法返回的是Object类型,需要强制转换为需要的类型。
- clone()方法是浅拷贝,如果需要实现深拷贝,则需要在重写clone()方法时进行手动处理。
示例代码:
public class Person implements Cloneable {
private String name;
private Address address;
// get/set方法省略
@Override
public Object clone() {
try {
Person person = (Person)super.clone();
person.address = (Address)address.clone();
return person;
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
public class Address implements Cloneable {
private String city;
private String street;
// get/set方法省略
@Override
public Object clone() {
try {
return super.clone();
} catch (CloneNotSupportedException e) {
e.printStackTrace();
return null;
}
}
}
// 测试代码
Person person1 = new Person();
person1.setName("张三");
Address address = new Address();
address.setCity("上海");
address.setStreet("浦东新区");
person1.setAddress(address);
Person person2 = (Person)person1.clone();
person2.getAddress().setCity("北京");
System.out.println(person1.getAddress().getCity()); //输出北京
- 使用对象的构造函数
在构造函数中,通过一个现有的对象来初始化另一个对象。这种方法也是一种浅拷贝,即如果原对象和复制对象都引用同一个对象,那么修改该共享对象时,原对象和复制对象都会受到影响。
示例代码:
public class Person {
private String name;
private Address address;
// 构造函数
public Person(Person person) {
this.name = person.getName();
this.address = person.getAddress();
}
// get/set方法省略
}
public class Address {
private String city;
private String street;
// 构造函数
public Address(Address address) {
this.city = address.getCity();
this.street = address.getStreet();
}
// get/set方法省略
}
// 测试代码
Person person1 = new Person();
person1.setName("张三");
Address address = new Address();
address.setCity("上海");
address.setStreet("浦东新区");
person1.setAddress(address);
Person person2 = new Person(person1);
person2.getAddress().setCity("北京");
System.out.println(person1.getAddress().getCity()); //输出北京
- 使用Java Bean的属性访问器
Java中,通过属性访问器来访问对象的属性值是一种常见的方式。使用该方式可以实现浅拷贝的效果。
示例代码:
public class Person {
private String name;
private Address address;
// get/set方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Address getAddress() {
return address;
}
public void setAddress(Address address) {
this.address = address;
}
}
public class Address {
private String city;
private String street;
// get/set方法
public String getCity() {
return city;
}
public void setCity(String city) {
this.city = city;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
}
// 测试代码
Person person1 = new Person();
person1.setName("张三");
Address address = new Address();
address.setCity("上海");
address.setStreet("浦东新区");
person1.setAddress(address);
Person person2 = new Person();
person2.setName(person1.getName());
person2.setAddress(person1.getAddress());
person2.getAddress().setCity("北京");
System.out.println(person1.getAddress().getCity()); //输出北京
什么是深拷贝?
深拷贝是指复制对象并创建一个新的对象,新对象和原对象互不影响,如果对象存在引用类型属性,会复制出一个新的对象来。如果其中一个对象对引用类型属性进行修改,另一个对象不会受到影响。
深拷贝的两种实现方式
- 通过序列化和反序列化实现深拷贝
在Java中,ObjectOutputStream和ObjectInputStream类可以将对象序列化为字节流,对字节流进行反序列化可以将对象还原回来。通过这种方式可以实现深拷贝的效果。
示例代码:
public class Person implements Serializable {
private String name;
private Address address;
// get/set方法省略
}
public class Address implements Serializable {
private String city;
private String street;
// get/set方法省略
}
// 测试代码
Person person1 = new Person();
person1.setName("张三");
Address address = new Address();
address.setCity("上海");
address.setStreet("浦东新区");
person1.setAddress(address);
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(person1);
out.flush();
ObjectInputStream in = new ObjectInputStream(new ByteArrayInputStream(byteOut.toByteArray()));
Person person2 = (Person)in.readObject();
person2.getAddress().setCity("北京");
System.out.println(person1.getAddress().getCity()); //输出上海
- 通过递归拷贝实现深拷贝
该方式只能用于对象中没有循环引用的场景。其细节在于通过递归方式遍历对象的所有属性,并对属性值进行拷贝,从而实现深拷贝的效果。
示例代码:
public class Person {
private String name;
private Address address;
// 构造函数
public Person(Person person) {
this.name = person.getName();
this.address = new Address(person.getAddress());
}
// get/set方法省略
}
public class Address {
private String city;
private String street;
// 构造函数
public Address(Address address) {
this.city = address.getCity();
this.street = address.getStreet();
}
// get/set方法省略
}
// 测试代码
Person person1 = new Person();
person1.setName("张三");
Address address = new Address();
address.setCity("上海");
address.setStreet("浦东新区");
person1.setAddress(address);
Person person2 = new Person(person1);
person2.getAddress().setCity("北京");
System.out.println(person1.getAddress().getCity()); //输出上海
总结
本文详细介绍了Java的深拷贝和浅拷贝的定义、区别及其实现方式,并提供了多个示例程序帮助读者更好的理解浅拷贝和深拷贝。在选择使用浅拷贝或深拷贝时,需要考虑对象之间的关系、应用场景和性能等方面,根据具体情况选择合适的实现方式。
本站文章如无特殊说明,均为本站原创,如若转载,请注明出处:Java的深拷贝与浅拷贝的几种实现方式 - Python技术站