深拷贝和浅拷贝的概念
浅拷贝:只对基本数据类型进行拷贝,针对于引用数据类型,只是拷贝了对象的引用,没有真实的创建一个新的对象就是浅拷贝
深拷贝:在对引用数据类型拷贝过程中,创建了一个新的对象,并且复制了对象内的所有成员变量,则是深拷贝
浅拷贝例子
创建了饮用水类,其中包括名称和生产厂家字段
package com.alibaba.fescar.core.protocol.test;
import lombok.Data;
@Data
public class Water {
private String name;
private String factory;
public Water(String name, String factory) {
this.name = name;
this.factory = factory;
}
@Override
public String toString() {
return "Water{" +
"name='" + name + '\'' +
", factory='" + factory + '\'' +
'}';
}
}
测试浅拷贝
package com.alibaba.fescar.core.protocol.test;
public class Test {
public static void main(String[] args) {
Water water = new Water("怡宝","华润");
// 此处既是浅拷贝
Water water1 = water;
System.out.println(water.toString());
System.out.println(water1.toString());
}
}
输出结果
如果浅拷贝对象操作属性呢,我们来试一下
package com.alibaba.fescar.core.protocol.test;
public class Test {
public static void main(String[] args) {
Water water = new Water("怡宝","华润");
// 此处既是浅拷贝
Water water1 = water;
// 浅拷贝对象操作属性
water1.setName("可乐");
water1.setFactory("可口可乐");
System.out.println(water.toString());
System.out.println(water1.toString());
}
}
输出结果
毫无疑问,源对象也会跟着改变 ,如果作为方法形参传入在操作属性呢,在来试一下
package com.alibaba.fescar.core.protocol.test;
public class Test {
public static void main(String[] args) {
Water water = new Water("怡宝","华润");
// 此处既是浅拷贝
Water water1 = water;
Test.test(water1);
System.out.println(water.toString());
System.out.println(water1.toString());
}
public static void test(Water water){
// 最为参数的浅拷贝对象操作属性
water.setName("可乐");
water.setFactory("可口可乐");
}
}
输出结果
结果很明显,就是浅拷贝对象指向的是源对象,对浅拷贝对象操作就是对源对象的操作,包括做为方法形参进行传递
Object类中的clone方法也是浅拷贝
深拷贝例子
同样以引用水对象为例,深拷贝就简单多了,创建一个新的对象就可以啦
实现方式:
- 通过序列化方式实现深拷贝,推荐实现方式
- 实现Cloneable接口重写clone方法实现(需要重写 clone 方法实现属性对象的拷贝,每层的每个对象都进行浅拷贝=深拷贝)比较麻烦 有需要可以自己实现
package com.alibaba.fescar.core.protocol.test;
import java.util.Objects;
public class Test {
public static void main(String[] args) {
Water water = new Water("怡宝","华润");
Water water1 = new Water("可乐","可口可乐");
System.out.println(water.toString());
System.out.println(water1.toString());
}
}
输出结果
序列化方式实现深拷贝
首先Water类必须实现序列化接口Serializable
package com.alibaba.fescar.core.protocol.test;
import lombok.Data;
import java.io.Serializable;
@Data
public class Water implements Serializable {
private String name;
private String factory;
public Water(String name, String factory) {
this.name = name;
this.factory = factory;
}
@Override
public String toString() {
return "Water{" +
"name='" + name + '\'' +
", factory='" + factory + '\'' +
'}';
}
}
定义获取深拷贝工具类
package com.alibaba.fescar.core.protocol.test;
import java.io.*;
import java.util.ArrayList;
import java.util.List;
public class DeepCopyUtils {
/**
* 获取一个对象的深拷贝对象
* @param t
* @param <T>
* @return
*/
public static <T> T getDeepCopy(T t) {
T deep = null;
try {
//在内存中开辟一块缓冲区,将对象序列化成流
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout);
out.writeObject(t);
//找到这一块缓冲区,将字节流反序列化成另一个对象
ByteArrayInputStream bais = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
deep =(T) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return deep;
}
/**
* 获取深拷贝对象list
* @param data
* @param <T>
* @return
*/
public static <T> List<T> getDeepCopyList(List<T> data){
List<T> deepList = new ArrayList<>();
try {
//在内存中开辟一块缓冲区,将对象序列化成流
ByteArrayOutputStream bout = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(bout);
out.writeObject(data);
//找到这一块缓冲区,将字节流反序列化成另一个对象
ByteArrayInputStream bais = new ByteArrayInputStream(bout.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bais);
deepList =(List<T>) ois.readObject();
} catch (IOException | ClassNotFoundException e) {
e.printStackTrace();
}
return deepList;
}
}
测试深拷贝对象
package com.alibaba.fescar.core.protocol.test;
public class Test {
public static void main(String[] args) {
Water water = new Water("怡宝", "华润");
Water water1 = DeepCopyUtils.getDeepCopy(water);
water1.setName("可乐");
water1.setFactory("可口可乐");
System.out.println(water.toString());
System.out.println(water1.toString());
}
}
输出结果