深拷贝和浅拷贝
深拷贝和浅拷贝是对对象的拷贝,一个对象中存在两种类型的属性,一种是基本数据类型,一种是实例对象的引用(引用数据类型)。
1:浅拷贝是指只会拷贝基本数据类型的值,以及实例对象的引用地址,并不会复制一份引用地址指向的对象,也就是浅拷贝出来的对象,内部的类属性指向的是同一个对象。
2:深拷贝是指既会拷贝基本类型的值,也会针对实例对象的引用地址指向的对象进行复制,深拷贝出来的对象,内部属性指向的不是同一个对象。
实现方式:
浅拷贝:
被复制类需要实现 Cloneable 接口,重写 clone 方法即可,对 person 类进行改造,使其可以支持浅拷贝。
public class Person implements Cloneable {
private String name; // 姓名
private int age; // 年龄
private String email; // 邮件
private String desc; // 描述
private Person friend; // 朋友
/* 重写 clone 方法,需要将权限改成 public ,直接调用父类的 clone 方法就好了 */
@Override
public Object clone() throws CloneNotSupportedException {
return super.clone();
}
}
public class PersonApp {
public static void main(String[] args) throws Exception {
// 初始化一个对象
Person person = new Person("张三",20,"123456@qq.com","我是张三");
// 复制对象
Person person1 = (Person) person.clone();
// 改变 person1 的属性值
person1.setName("我是张三的克隆对象");
// 修改 person age 的值
person1.setAge(22);
System.out.println("person对象:"+person);
System.out.println();
System.out.println("person1对象:"+person1);
}
}
// person对象:Person{name='张三', age=20, email='123456@qq.com', desc='我是张三'}
// person1对象:Person{name='我是张三的克隆对象', age=22, email='123456@qq.com', desc='我是张三'}
原因:
String 和 Integer 等包装类都是不可变的对象。
当需要 修改 不可变对象的值时,需要在内存中生成一个新的对象来存放新的值,然后将原来的引用指向新的地址。
所以在这里我们修改了 person1 对象的 name 属性值,person1 对象的 name 字段指向了内存中新的 name 对象,但是我们并没有改变 person 对象的 name 字段的指向,所以 person 对象的 name 还是指向内存中原来的 name 地址,也就没有变化。
深拷贝:
相对于浅拷贝,深拷贝是一种完全拷贝,无论是值类型还是引用类型都会完完全全的拷贝一份,在内存中生成一个新的对象。拷贝对象和被拷贝对象没有任何关系,互不影响。
实现方式
实现Cloneable接口
class Address{
String name;
String eCode;
public Address( String na, String eC;)
{
this.name = na;
this.eCode = eC;
}
}
public class Person implements Cloneable {
private String name; // 姓名
private int age; // 年龄
private String email; // 邮件
private Address address; //
private Person friend; // 朋友
/* 重写 clone 方法,需要将权限改成 public ,直接调用父类的 clone 方法就好了 */
@Override
public Object clone() throws CloneNotSupportedException {
Person newp = new Person();
newp.name = new String(this.name);
newp.age = this.age;
newp.email = new String(this.email);
newp.address = new Address(this.address.name, this.address.eCode);
return newp;
}
}
实现Serializable接口
protected Son deepClone() throws IOException, ClassNotFoundException {
Son son=null;
//在内存中创建一个字节数组缓冲区,所有发送到输出流的数据保存在该字节数组中
//默认创建一个大小为32的缓冲区
ByteArrayOutputStream byOut=new ByteArrayOutputStream();
//对象的序列化输出
ObjectOutputStream outputStream=new ObjectOutputStream(byOut);//通过字节数组的方式进行传输
outputStream.writeObject(this); //将当前student对象写入字节数组中
//在内存中创建一个字节数组缓冲区,从输入流读取的数据保存在该字节数组缓冲区
ByteArrayInputStream byIn=new ByteArrayInputStream(byOut.toByteArray()); //接收字节数组作为参数进行创建
ObjectInputStream inputStream=new ObjectInputStream(byIn);
son=(Son) inputStream.readObject(); //从字节数组中读取
return son;
}
实现 Serializable 接口方式也可以实现深拷贝,而且这种方式还可以解决多层克隆的问题,多层克隆就是引用类型里面又有引用类型,层层嵌套下去。