深拷贝
概念
深拷贝是一种创建新对象的方法,它不仅复制对象本身,还会递归地复制对象内部的所有引用类型。这意味着对于对象中的每个引用类型成员,都会创建一个新的实例,并且将原对象中的数据复制到新对象中。这样可以确保新对象与原对象完全独立,修改其中一个对象的内容不会影响另一个对象。
特点
对于基本类型的数据成员,会复制其值。
对于引用类型的数据成员,会递归地复制整个对象。
实现方式
手动实现
遍历对象的所有字段,对于引用类型字段,递归地进行深拷贝。
对于基本类型字段,直接复制值。
代码示例
被拷贝的对象:Person、Address,Person中聚合Address用于测试深拷贝
package com.ysj.correlation.deepShallowCopy.deep.manual;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;
/**
* 人
*/
@Data
@AllArgsConstructor
@ToString
public class Person {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private int age;
/**
* 地址
*/
private Address address;
}
package com.ysj.correlation.deepShallowCopy.deep.manual;
import lombok.*;
/**
* 地址
*/
@Data
@AllArgsConstructor
@ToString
public class Address {
/**
* 城市
*/
private String city;
/**
* 街道
*/
private String street;
}
客户端:DeepCopyClient,deepCopy()手动实现深拷贝
package com.ysj.correlation.deepShallowCopy.deep.manual;
public class DeepCopyClient {
/**
* 手动实现深拷贝
* @param original
* @return
*/
public static Person deepCopy(Person original) {
if (original == null) {
return null;
}
Address addressCopy = new Address(original.getAddress().getStreet(), original.getAddress().getCity());
return new Person(original.getName(), original.getAge(), addressCopy);
}
public static void main(String[] args) {
Address address = new Address("重庆","长生桥");
Person person = new Person("小帅", 30, address);
Person personCopy = deepCopy(person);
System.out.println("原始: " + person);
System.out.println("复制: " + personCopy);
person.getAddress().setStreet("同景");
System.out.println("修改后:");
System.out.println("原始: " + person);
System.out.println("复制: " + personCopy);
}
}
序列化和反序列化实现
将对象序列化为字节流或某种文本格式(如 JSON)。
再从序列化的数据中反序列化出一个新对象。
代码示例
被拷贝的对象:Person、Address,Person中聚合Address用于测试深拷贝,都实现Serializable
package com.ysj.correlation.deepShallowCopy.deep.serialization;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;
import java.io.Serializable;
/**
* 人
*/
@Data
@AllArgsConstructor
@ToString
public class Person implements Serializable {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private int age;
/**
* 地址
*/
private Address address;
}
package com.ysj.correlation.deepShallowCopy.deep.serialization;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;
import java.io.Serializable;
/**
* 地址
*/
@Data
@AllArgsConstructor
@ToString
public class Address implements Serializable {
/**
* 城市
*/
private String city;
/**
* 街道
*/
private String street;
}
客户端:DeepCopyClient,deepCopy()序列化和反序列化实现深拷贝
package com.ysj.correlation.deepShallowCopy.deep.serialization;
import java.io.*;
public class DeepCopyClient {
/**
* 序列化和反序列化实现深拷贝
* @param original
* @return
* @param <T>
* @throws IOException
* @throws ClassNotFoundException
*/
public static <T> T deepCopy(T original) throws IOException, ClassNotFoundException {
ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
ObjectOutputStream out = new ObjectOutputStream(byteOut);
out.writeObject(original);
ByteArrayInputStream byteIn = new ByteArrayInputStream(byteOut.toByteArray());
ObjectInputStream in = new ObjectInputStream(byteIn);
return (T) in.readObject();
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
Address address = new Address("重庆","长生桥");
Person person = new Person("小帅", 30, address);
Person personCopy = deepCopy(person);
System.out.println("原始: " + person);
System.out.println("复制: " + personCopy);
person.getAddress().setStreet("同景");
System.out.println("修改后:");
System.out.println("原始: " + person);
System.out.println("复制: " + personCopy);
}
}
第三方库实现
org.apache.commons.lang3.SerializationUtils.clone() 实现深拷贝,推荐使用(被拷贝对象必须实现Serializable)
com.fasterxml.jackson.databind.ObjectMapper的 writeValueAsString() 和 readValue() 实现深拷贝,但是不推荐。(与序列化和反序列化实现类似,只不过使用json字符串实现序列化和反序列化)
cn.hutool.core.util.ObjectUtil.clone() 实现深拷贝
被拷贝对象实现Serializable接口(如果没实现返回null),直接就是深拷贝,推荐使用
被拷贝对象实现Cloneable接口,调用自己的clone()实现深拷贝
代码示例(以hutool工具为例)
客户端:DeepCopyClient,deepCopy()调用ObjectUtil.clone()实现深拷贝,Person和Address使用实现了Serializable的
package com.ysj.correlation.deepShallowCopy.deep.party3;
import cn.hutool.core.util.ObjectUtil;
import com.ysj.correlation.deepShallowCopy.deep.serialization.Address;
import com.ysj.correlation.deepShallowCopy.deep.serialization.Person;
import java.io.*;
public class DeepCopyClient {
/**
* ObjectUtil.clone()实现深拷贝
*
* @param original
* @param <T>
* @return
* @throws IOException
* @throws ClassNotFoundException
*/
public static <T> T deepCopy(T original) {
return ObjectUtil.clone(original);
}
public static void main(String[] args) throws IOException, ClassNotFoundException {
Address address = new Address("重庆", "长生桥");
Person person = new Person("小帅", 30, address);
Person personCopy = deepCopy(person);
System.out.println("原始: " + person);
System.out.println("复制: " + personCopy);
person.getAddress().setStreet("同景");
System.out.println("修改后:");
System.out.println("原始: " + person);
System.out.println("复制: " + personCopy);
}
}
浅拷贝
概念
浅拷贝是指创建一个新对象,这个新对象具有原始对象属性值的一份精确拷贝。如果属性是基本类型(如整数、浮点数、字符串等),拷贝的就是基本类型的值;如果属性是引用类型(如对象或者数组),拷贝的就是内存地址,即新旧对象共享同一块内存区域。
特点
对于基本数据类型的字段,会复制其值。
对于引用数据类型的字段,只会复制其引用(内存地址)。
实现方式
手动实现
被拷贝的对象:Person、Address,Person中聚合Address用于测试浅拷贝
package com.ysj.correlation.deepShallowCopy.deep.manual;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;
/**
* 人
*/
@Data
@AllArgsConstructor
@ToString
public class Person {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private int age;
/**
* 地址
*/
private Address address;
}
package com.ysj.correlation.deepShallowCopy.deep.manual;
import lombok.*;
/**
* 地址
*/
@Data
@AllArgsConstructor
@ToString
public class Address {
/**
* 城市
*/
private String city;
/**
* 街道
*/
private String street;
}
客户端:DeepCopyClient,deepCopy()手动实现浅拷贝
package com.ysj.correlation.deepShallowCopy.shallow.manual;
public class ShallowCopyClient {
/**
* 手动实现浅拷贝
* @param original
* @return
*/
public static Person shallowCopy(Person original) {
if (original == null) {
return null;
}
return new Person(original.getName(), original.getAge(), original.getAddress());
}
public static void main(String[] args) {
Address address = new Address("重庆","长生桥");
Person person = new Person("小帅", 30, address);
Person personCopy = shallowCopy(person);
System.out.println("原始: " + person);
System.out.println("复制: " + personCopy);
person.getAddress().setStreet("同景");
System.out.println("修改后:");
System.out.println("原始: " + person);
System.out.println("复制: " + personCopy);
}
}
浅拷贝构造器实现
如果类提供了适当的构造器,可以直接使用这些构造器来创建新对象。
对于引用类型成员,直接使用原对象的引用。
代码示例
被拷贝的对象:Person、Address,Person中聚合Address用于测试浅拷贝,浅拷贝构造器进行浅拷贝
package com.ysj.correlation.deepShallowCopy.shallow.constructor;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;
/**
* 人
*/
@Data
@AllArgsConstructor
@ToString
public class Person {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private int age;
/**
* 地址
*/
private Address address;
/**
* 浅拷贝构造器
* @param original
*/
public Person(Person original) {
this.name = original.name;
this.age = original.age;
this.address = original.address; // 只复制引用
}
}
package com.ysj.correlation.deepShallowCopy.shallow.constructor;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;
/**
* 地址
*/
@Data
@AllArgsConstructor
@ToString
public class Address {
/**
* 城市
*/
private String city;
/**
* 街道
*/
private String street;
}
客户端:DeepCopyClient,使用浅拷贝构造器浅拷贝
package com.ysj.correlation.deepShallowCopy.shallow.constructor;
public class ShallowCopyClient {
public static void main(String[] args) {
Address address = new Address("重庆","长生桥");
Person person = new Person("小帅", 30, address);
// 使用浅拷贝构造器浅拷贝
Person personCopy = new Person(person);
System.out.println("原始: " + person);
System.out.println("复制: " + personCopy);
person.getAddress().setStreet("同景");
System.out.println("修改后:");
System.out.println("原始: " + person);
System.out.println("复制: " + personCopy);
}
}
clone()方法实现
代码示例
被拷贝的对象:Person、Address,Person中聚合Address用于测试浅拷贝,都实现Cloneable,并重写clone()方法
package com.ysj.correlation.deepShallowCopy.shallow.cloneable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;
/**
* 人
*/
@Data
@AllArgsConstructor
@ToString
public class Person implements Cloneable {
/**
* 姓名
*/
private String name;
/**
* 年龄
*/
private int age;
/**
* 地址
*/
private Address address;
public Person clone() {
try {
return (Person) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
package com.ysj.correlation.deepShallowCopy.shallow.cloneable;
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.ToString;
/**
* 地址
*/
@Data
@AllArgsConstructor
@ToString
public class Address implements Cloneable{
/**
* 城市
*/
private String city;
/**
* 街道
*/
private String street;
public Address clone() {
try {
return (Address) super.clone();
} catch (CloneNotSupportedException e) {
throw new RuntimeException(e);
}
}
}
客户端:DeepCopyClient,shallowCopy调用clone()实现浅拷贝
package com.ysj.correlation.deepShallowCopy.shallow.cloneable;
public class ShallowCopyClient {
/**
* clone()方法实现浅拷贝
* @param original
* @return
*/
public static Person shallowCopy(Person original) {
if (original == null) {
return null;
}
return original.clone();
}
public static void main(String[] args) {
Address address = new Address("重庆","长生桥");
Person person = new Person("小帅", 30, address);
Person personCopy = shallowCopy(person);
System.out.println("原始: " + person);
System.out.println("复制: " + personCopy);
person.getAddress().setStreet("同景");
System.out.println("修改后:");
System.out.println("原始: " + person);
System.out.println("复制: " + personCopy);
}
}
第三方库实现
cn.hutool.core.bean.BeanUtil.copyProperties() 实现浅拷贝,推荐使用
代码实现
package com.ysj.correlation.deepShallowCopy.shallow.party3;
import cn.hutool.core.bean.BeanUtil;
import com.ysj.correlation.deepShallowCopy.shallow.manual.Address;
import com.ysj.correlation.deepShallowCopy.shallow.manual.Person;
public class ShallowCopyClient {
/**
* BeanUtil.copyProperties()实现浅拷贝
*
* @param original
* @return
*/
public static Person shallowCopy(Person original) {
if (original == null) {
return null;
}
return BeanUtil.copyProperties(original, Person.class);
}
public static void main(String[] args) {
Address address = new Address("重庆", "长生桥");
Person person = new Person("小帅", 30, address);
Person personCopy = shallowCopy(person);
System.out.println("原始: " + person);
System.out.println("复制: " + personCopy);
person.getAddress().setStreet("同景");
System.out.println("修改后:");
System.out.println("原始: " + person);
System.out.println("复制: " + personCopy);
}
}
评论区