Java中的对象拷贝主要分为:引用拷贝,浅拷贝(Shallow Copy)、深拷贝(Deep Copy)。
1、引用拷贝
并没有创建一个新的对象,两个对象都指向同一个引用地址。
对于对象内的数据,不管是基本类型还是引用类型的修改,都会影响到另一个对象。
2、浅拷贝
创建一个新对象,并对对象内的每个数据进行拷贝。
- 数据属性是基本类型或String,拷贝的就是基本类型或String的值;
- 数据属性是引用类型,拷贝的就是引用(即内存地址),如果内存地址内的值发生改变,就会影响到另一个对象。
实现对象拷贝的类,必须实现Cloneable接口,并覆写clone()方法。
必须重写Object中的clone()方法,要重写clone()方法,就必须实现Cloneable接口
如果重写了Object中的clone()方法,没有实现Cloneable接口,会报错java.lang.CloneNotSupportedException
protected native Object clone() throws CloneNotSupportedException;
3、深拷贝
创建一个新对象,并对对象内的每个数据进行拷贝。
如果数据类型是引用类型,则继续进行浅拷贝(本质是创建新对象,赋值),直到所有引用类型都是新创建的对象。
深拷贝实现方式:层层clone()实现深拷贝,序列化实现深拷贝
3.1、层层clone()实现深拷贝
对象的所有引用类型,都要进行引用类型的再次clone(),赋给对象
3.2、序列化实现深拷贝
对象的所有引用类型,都要实现Serializable接口
举例:
- Person类持有三个变量(String类型,基本类型,引用类型),String name,int age,Address address
Person类
public class Person implements Cloneable, Serializable {
//姓名
private String name;
// 年龄
private int age;
// 联系地址
private Address address;
public Person(String name, int age, Address address) {
this.name = name;
this.age = age;
this.address = address;
}
//省略get、set、toString方法
/**
* 如果一个对象内部只有基本数据类型,则 clone() 方法获取到的就是这个对象的深拷贝。
* 而如果其内部还有引用数据类型,那用 clone() 方法就是一次浅拷贝的操作。
*/
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
/**
* 对对象内的每一级引用类型(除String),做浅拷贝,即为深拷贝
*/
public Object deepClone() throws CloneNotSupportedException {
Person person = (Person) super.clone();
Address address = (Address) getAddress().clone();
person.setAddress(address);
return person;
}
/**
* 利用串行化来做深复制
*/
public Object deepCloneBySerialize() {
try {
//写入对象
ByteArrayOutputStream bo = new ByteArrayOutputStream();
ObjectOutputStream os = new ObjectOutputStream(bo);
os.writeObject(this);
//读取对象
ByteArrayInputStream bi = new ByteArrayInputStream(bo.toByteArray());
ObjectInputStream oi = new ObjectInputStream(bi);
return (oi.readObject());
} catch (IOException e) {
e.printStackTrace();
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
return null;
}
}
Address类
public class Address implements Cloneable, Serializable {
private String name;
public Address(String name) {
this.name = name;
}
//省略get、set、toString方法
@Override
protected Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
测试Demo
public class CloneDemo {
public static void main(String[] args) throws CloneNotSupportedException {
//引用拷贝
System.out.println("-------- 引用拷贝 ----------");
Person p = new Person("本人",18, new Address("湖南"));
Person p1 = p;
System.out.println(p);
System.out.println(p1);
System.out.println(p == p1);
p1.setName("本人copy");
p1.setAge(666);
p1.getAddress().setName("上海");
System.out.println(p);
System.out.println(p1);
//浅拷贝
System.out.println();
System.out.println("-------- 浅拷贝 ----------");
p = new Person("本人",18, new Address("湖南"));
p1 = (Person)p.clone();
System.out.println(p);
System.out.println(p1);
System.out.println("--------convert--");
p1.setName("本人copy");
p1.setAge(666);
p1.getAddress().setName("上海");
System.out.println(p);
System.out.println(p1);
//深拷贝实现方式1
System.out.println();
System.out.println("-------- 深拷贝 ----------");
p = new Person("本人",18, new Address("湖南"));
p1 = (Person)p.deepClone();
System.out.println(p);
System.out.println(p1);
System.out.println("--------convert--");
p1.setName("本人copy");
p1.setAge(666);
p1.getAddress().setName("上海");
System.out.println(p);
System.out.println(p1);
//深拷贝实现方式2 serialize
System.out.println();
System.out.println("-------- 深拷贝 serialize ----------");
p = new Person("本人",18, new Address("湖南"));
p1 = (Person)p.deepCloneBySerialize();
System.out.println(p);
System.out.println(p1);
System.out.println("--------convert--");
p1.setName("本人copy");
p1.setAge(666);
p1.getAddress().setName("上海");
System.out.println(p);
System.out.println(p1);
System.out.println("-------- xxxxx ----------");
}
}
测试结果:
-------- 引用拷贝 ----------
Person{name='本人', age=18, address=Student{name='湖南'}}
Person{name='本人', age=18, address=Student{name='湖南'}}
true
Person{name='本人copy', age=666, address=Student{name='上海'}}
Person{name='本人copy', age=666, address=Student{name='上海'}}
-------- 浅拷贝 ----------
Person{name='本人', age=18, address=Student{name='湖南'}}
Person{name='本人', age=18, address=Student{name='湖南'}}
--------convert--
Person{name='本人', age=18, address=Student{name='上海'}}
Person{name='本人copy', age=666, address=Student{name='上海'}}
-------- 深拷贝 ----------
Person{name='本人', age=18, address=Student{name='湖南'}}
Person{name='本人', age=18, address=Student{name='湖南'}}
--------convert--
Person{name='本人', age=18, address=Student{name='湖南'}}
Person{name='本人copy', age=666, address=Student{name='上海'}}
-------- 深拷贝 serialize ----------
Person{name='本人', age=18, address=Student{name='湖南'}}
Person{name='本人', age=18, address=Student{name='湖南'}}
--------convert--
Person{name='本人', age=18, address=Student{name='湖南'}}
Person{name='本人copy', age=666, address=Student{name='上海'}}
-------- xxxxx ----------