什么是浅拷贝
需要拷贝的源对象中的属性存在引用对象,拷贝后的对象中修改此引用对象的属性之后,源对象的引用值也跟着修改
clone方法
clone()方法:对于基本类型是直接复制创建副本,对于引用类型,则是复制一个引用地址,不会复制引用所指对象
1.浅拷贝案例:
创建两个实体对象,Person,Address
package com.yunsuibi.shallow.entity;
public class Person implements Cloneable {
private int age;
private String name;
private Address address;
public Person(int age, String name, Address address) {
this.age = age;
this.name = name;
this.address = address;
}
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
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 String display() {
return "Person [age=" + age + ", name=" + name + ", address=" + address + "]";
}
}
package com.yunsuibi.shallow.entity;
public class Address {
private String province;
private String street;
public Address(String province, String street) {
this.province = province;
this.street = street;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
@Override
public String toString() {
return "Address [province=" + province + ", street=" + street + "]";
}
}
1.测试
public static void main(String[] args) throws Exception {
Person person = new Person(15, "张三", new Address("四川", "天府二街"));
Person clonePerson = (Person) person.clone();
System.out.println(person);
System.out.println(clonePerson);
System.out.println(person.display());
System.out.println(clonePerson.display());
clonePerson.setName("王麻子");
clonePerson.setAge(20);
Address address = clonePerson.getAddress();
address.setStreet("天府四街");
System.out.println(person.display());
System.out.println(clonePerson.display());
}
打印结果:
com.yunsuibi.shallow.entity.Person@7852e922
com.yunsuibi.shallow.entity.Person@4e25154f
Person [age=15, name=张三, address=Address [province=四川, street=天府二街]]
Person [age=15, name=张三, address=Address [province=四川, street=天府二街]]
Person [age=15, name=张三, address=Address [province=四川, street=天府四街]]
Person [age=20, name=王麻子, address=Address [province=四川, street=天府四街]]
注意:此时修改了address的复制对象后,源对象内容也跟着修改了,因此有了浅拷贝和深拷贝一说
2.下面案例讲解常用深拷贝方式:通过序列化实现拷贝
创建一个序列化对象
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;
import java.io.Serializable;
public class DeepClone implements Serializable{
/**
* 利用序列化和反序列化进行对象的深拷贝
* @return
* @throws Exception
*/
protected Object deepClone() throws Exception{
//序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(this);
//反序列化
ObjectInputStream ois = new ObjectInputStream(new ByteArrayInputStream(bos.toByteArray()));
return ois.readObject();
}
}
Person对象修改为以下状态:
package com.yunsuibi.thorough2.entity;
public class Person extends DeepClone {
private int age;
private String name;
private Address address;
public Person(int age, String name, Address address) {
this.age = age;
this.name = name;
this.address = address;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
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 String display() {
return "Person [age=" + age + ", name=" + name + ", address=" + address + "]";
}
}
Address对象修改为以下状态
package com.yunsuibi.thorough2.entity;
public class Address extends DeepClone {
private String province;
private String street;
public Address(String province, String street) {
this.province = province;
this.street = street;
}
public String getProvince() {
return province;
}
public void setProvince(String province) {
this.province = province;
}
public String getStreet() {
return street;
}
public void setStreet(String street) {
this.street = street;
}
@Override
public String toString() {
return "Address [province=" + province + ", street=" + street + "]";
}
}
2.测试
public static void main(String[] args) throws CloneNotSupportedException {
Person person = new Person(15, "张三", new Address("四川", "天府二街"));
Person clonePerson = (Person) person.clone();
System.out.println(person);
System.out.println(clonePerson);
System.out.println(person.display());
System.out.println(clonePerson.display());
clonePerson.setName("王麻子");
clonePerson.setAge(20);
Address address = clonePerson.getAddress();
address.setStreet("天府四街");
System.out.println(person.display());
System.out.println(clonePerson.display());
}
打印结果:
com.yunsuibi.thorough.entity.Person@7852e922
com.yunsuibi.thorough.entity.Person@4e25154f
Person [age=15, name=张三, address=Address [province=四川, street=天府二街]]
Person [age=15, name=张三, address=Address [province=四川, street=天府二街]]
Person [age=15, name=张三, address=Address [province=四川, street=天府二街]]
Person [age=20, name=王麻子, address=Address [province=四川, street=天府四街]]
此时修改了拷贝对象后,源对象没有跟着改变,深拷贝成功
还有一种方式,源对象需要实现Cloneable接口,重写clone方法,其中包含的所有引用对象也需要实现Cloneable接口,重写clone,
在源对象中clone中需要手动对引用对象进行clone并set源对象中,这种方式如果源对象中引用对象过多,代码就会冗余.不建议使用这种方式
个人博客 云随笔 为java而生
可以关注下博主的公众号,实时推送解决方案!