原型模式
原型模式实现的操作就是基于原型实例, 创建一个新的对象.
一般我们获取一个对象的复制版, 就是直接new一个新的对象, 传入相同的参数.
但是, 当构造过程过于复杂,比如需要大量计算
或者构造过程依赖外部资源, 比如要连接好数据库, 或者要读写外部文件
此时获取一个相同的类对象副本就过于复杂.
因此我们对这种复杂的类的封装时, 要加入一个便于复制的方法接口.
Java自身带的Cloneable接口以及Java自带的clone方法有很多不安全因素, 容易因判断错深浅拷贝而导致bug, 同时也因直接的复制内存破坏类的封装性.
Java中实现原型模式的方法推荐方式:
(一)深拷贝场景
1. Apache SerializationUtils(有 Serializable)
Apache Commons Lang 的 SerializationUtils 基于序列化 / 反序列化实现对象拷贝,本质是深拷贝(前提是所有成员变量都实现 Serializable)
注意事项:
- Serializable 是标记接口,无需实现任何方法,但建议显式声明 serialVersionUID 避免序列化兼容问题;
- 若成员变量是
transient(瞬态),序列化时会被忽略,拷贝后该字段为默认值(如 null/0); SerializationUtils不支持拷贝null对象,会直接抛出 NullPointerException,建议在 deepClone 方法中增加判空。
前提: 需要安装maven包管理器, 并且引入commons-lang3依赖
pom.xml中加入依赖项:
<dependencies>
<!-- 引入 commons-lang3 依赖 -->
<dependency>
<groupId>org.apache.commons</groupId> <!-- 组织ID -->
<artifactId>commons-lang3</artifactId> <!-- 组件ID -->
<version>3.20.0</version> <!-- 版本号(最新稳定版) -->
</dependency>
</dependencies>
定义对象类及其嵌套类如下:
java
// 可变对象:阅读的书籍(包含可修改的属性)
class ReadBook implements Serializable {
private String bookName; // 书名
private Integer pageCount; // 页数(可变属性)
// 无参构造器
public ReadBook() {}
// 全参构造器
public ReadBook(String bookName, Integer pageCount) {
this.bookName = bookName;
this.pageCount = pageCount;
}
// 【核心】ReadBook的拷贝构造器(深拷贝)
public ReadBook(ReadBook original) {
this.bookName = original.bookName;
this.pageCount = original.pageCount; // Integer是不可变类型,直接赋值
}
// getter/setter(包含可变属性的setter)
public String getBookName() { return bookName; }
public void setBookName(String bookName) { this.bookName = bookName; }
public Integer getPageCount() { return pageCount; }
public void setPageCount(Integer pageCount) { this.pageCount = pageCount; }
@Override
public String toString() {
return "ReadBook{" +
"bookName='" + bookName + '\'' +
", pageCount=" + pageCount +
'}';
}
}
// 嵌套在User中的引用类, 必须实现Serializable接口
class Address implements Serializable {
private String province;
private String city;
public Address(String province, String city) {
this.province = province;
this.city = city;
}
// getter/setter
public String getProvince() { return province; }
public void setProvince(String province) { this.province = province; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
'}';
}
}
// 将要实现拷贝的类定义
class User implements Serializable {
private Integer ID;
private String name;
private Address address;
private List<ReadBook> hobbies;
public User(Integer id, String name, Address addr, List<ReadBook> hobbies) {
this.ID = id;
this.name = name;
this.address = addr;
this.hobbies = hobbies;
}
// 原型方法 基于 SerializationUtils 实现深拷贝
public User deepClone() {
return SerializationUtils.clone(this);
}
// getter/setter
public Integer getID() { return ID; }
public void setID(Integer ID) { this.ID = ID; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Address getAddress() { return address; }
public List<ReadBook> getHobbies() { return hobbies; }
@Override
public String toString() {
return "User{" +
"id=" + ID +
", name='" + name + '\'' +
", address=" + address +
", hobbies=" + hobbies +
'}';
}
}
调用并测试:
java
import org.apache.commons.lang3.SerializationUtils;
import java.io.Serializable;
import java.util.ArrayList;
import java.util.List;
public class ProtoType {
public static void main(String[] args) {
// 创建原始对象
Address originAddr = new Address("内蒙古", "鄂尔多斯市");
List<ReadBook> hobbies = new ArrayList<>();
hobbies.add(new ReadBook("可汗大点兵", 520));
hobbies.add(new ReadBook("骑兵的自我修养", 1001));
User originUser = new User(1001, "张三", originAddr, hobbies);
System.out.println("======== 原始对象 ========");
System.out.println(originUser);
// 执行深拷贝
User newUser01 = originUser.deepClone();
System.out.println("======== 拷贝对象 ========");
System.out.println(newUser01);
// 修改拷贝后的各项属性, 验证拷贝结果
newUser01.setName("李四");
newUser01.getAddress().setCity("包头");
newUser01.getHobbies().get(0).setPageCount(21);
newUser01.getHobbies().get(1).setBookName("敖包相会");
// 4. 验证原始对象是否被影响
System.out.println("\n======== 原始对象(修改拷贝后) ========");
System.out.println(originUser);
System.out.println("======== 拷贝对象(修改拷贝后) ========");
System.out.println(newUser01);
}
}
输出结果:
======== 原始对象 ========
User{id=1001, name='张三', address=Address{province='内蒙古', city='鄂尔多斯市'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=520}, ReadBook{bookName='骑兵的自我修养', pageCount=1001}]}
======== 拷贝对象 ========
User{id=1001, name='张三', address=Address{province='内蒙古', city='鄂尔多斯市'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=520}, ReadBook{bookName='骑兵的自我修养', pageCount=1001}]}
======== 原始对象(修改拷贝后) ========
User{id=1001, name='张三', address=Address{province='内蒙古', city='鄂尔多斯市'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=520}, ReadBook{bookName='骑兵的自我修养', pageCount=1001}]}
======== 拷贝对象(修改拷贝后) ========
User{id=1001, name='李四', address=Address{province='内蒙古', city='包头'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=21}, ReadBook{bookName='敖包相会', pageCount=1001}]}
2. Jackson(无 Serializable)
利用 Jackson 的序列化 / 反序列化能力实现深拷贝, (无需实现Serializable)
所有嵌套对象都会被重新实例化(内存地址不同),修改不影响原始对象;
支持复杂对象结构(集合、多层嵌套等),兼容性强。
前提: 需要安装maven包管理器, 并且引入Jackson依赖
pom.xml中加入依赖项:
<dependencies>
<!-- 引入 Jackson 依赖 -->
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-databind</artifactId>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-annotations</artifactId>
<version>2.17.0</version>
</dependency>
<dependency>
<groupId>com.fasterxml.jackson.core</groupId>
<artifactId>jackson-core</artifactId>
<version>2.17.0</version>
</dependency>
</dependencies>
定义类及其中嵌套的类
需要注意的是,
Serializable 是 JDK 原生序列化的「标记接口」(接口内无任何方法),作用是告诉 JVM:「这个类可以被 JDK 的序列化机制处理」。
而 Jackson 是基于 JSON 文本序列化 的独立框架,它的核心是「反射解析字段 + 文本转换」,完全不依赖 JDK 原生序列化机制,因此:
不需要类实现 Serializable 接口;
即使实现了,Jackson 也不会使用这个接口的任何逻辑(属于冗余代码)。
Jackson 实现深拷贝的核心流程是:
原始对象 → 序列化(转 JSON 字符串) → 反序列化(JSON → 新对象)
反序列化阶段是关键:Jackson 要把 JSON 字符串转成 Java 对象,需要通过「反射」创建对象实例,默认逻辑是:
- 先通过反射调用类的 无参构造器 创建一个空对象(new User() / new Address());
- 再通过反射调用 setter 方法(或直接赋值字段),把 JSON 中的值填充到空对象中。
所以定义拷贝类及其中的嵌套类时必须都有无参构造, 否则会抛异常
java
// 可变对象:阅读的书籍(包含可修改的属性)
class ReadBook {
private String bookName; // 书名
private Integer pageCount; // 页数(可变属性)
// 注意:无参构造器(Jackson反序列化必需)
public ReadBook() {}
// 全参构造器
public ReadBook(String bookName, Integer pageCount) {
this.bookName = bookName;
this.pageCount = pageCount;
}
// 【核心】ReadBook的拷贝构造器(深拷贝)
public ReadBook(ReadBook original) {
this.bookName = original.bookName;
this.pageCount = original.pageCount; // Integer是不可变类型,直接赋值
}
// getter/setter(包含可变属性的setter)
public String getBookName() { return bookName; }
public void setBookName(String bookName) { this.bookName = bookName; }
public Integer getPageCount() { return pageCount; }
public void setPageCount(Integer pageCount) { this.pageCount = pageCount; }
@Override
public String toString() {
return "ReadBook{" +
"bookName='" + bookName + '\'' +
", pageCount=" + pageCount +
'}';
}
}
// 嵌套类:删除无用的 Serializable 接口(Jackson拷贝无需此接口)
class Address {
private String province;
private String city;
// 注意:无参构造器(Jackson反序列化必需)
public Address() {}
public Address(String province, String city) {
this.province = province;
this.city = city;
}
// getter/setter
public String getProvince() { return province; }
public void setProvince(String province) { this.province = province; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
'}';
}
}
// 拷贝类:删除无用的 Serializable 接口
class User {
private Integer ID;
private String name;
private Address address;
private List<ReadBook> hobbies;
// 初始化Jackson对象映射器
private static final ObjectMapper OBJECT_MAPPER = new ObjectMapper();
// 注意:无参构造器(Jackson反序列化必需)
public User() {}
public User(Integer id, String name, Address addr, List<ReadBook> hobbies) {
this.ID = id;
this.name = name;
this.address = addr;
this.hobbies = hobbies;
}
// 深拷贝:基于Jackson序列化/反序列化
public User deepClone() throws JsonProcessingException {
// 序列化:对象转JSON字符串
String json = OBJECT_MAPPER.writeValueAsString(this);
// 反序列化:JSON字符串转新对象(所有嵌套对象都会重新创建)
return OBJECT_MAPPER.readValue(json, User.class);
}
// getter/setter
public Integer getID() { return ID; }
public void setID(Integer ID) { this.ID = ID; }
public String getName() { return name; }
public void setName(String name) { this.name = name; }
public Address getAddress() { return address; }
public List<ReadBook> getHobbies() { return hobbies; }
@Override
public String toString() {
return "User{" +
"id=" + ID +
", name='" + name + '\'' +
", address=" + address +
", hobbies=" + hobbies +
'}';
}
}
实例化并测试代码:
java
import com.fasterxml.jackson.core.JsonProcessingException;
import com.fasterxml.jackson.databind.ObjectMapper;
import java.util.ArrayList;
import java.util.List;
public class ProtoType {
public static void main(String[] args) {
// 创建原始对象
Address originAddr = new Address("内蒙古", "鄂尔多斯市");
List<ReadBook> hobbies = new ArrayList<>();
hobbies.add(new ReadBook("可汗大点兵", 520));
hobbies.add(new ReadBook("骑兵的自我修养", 1001));
User originUser = new User(1001, "张三", originAddr, hobbies);
System.out.println("======== 原始对象 ========");
System.out.println(originUser);
// 执行深拷贝
try {
// 执行深拷贝
User newUser01 = originUser.deepClone();
System.out.println("======== 拷贝对象 ========");
System.out.println(newUser01);
// 修改拷贝后的各项属性, 验证拷贝结果
newUser01.setName("李四");
newUser01.getAddress().setCity("包头");
newUser01.getHobbies().get(0).setPageCount(21);
newUser01.getHobbies().get(1).setBookName("敖包相会");
// 4. 验证原始对象是否被影响
System.out.println("\n======== 原始对象(修改拷贝后) ========");
System.out.println(originUser);
System.out.println("======== 拷贝对象(修改拷贝后) ========");
System.out.println(newUser01);
} catch (JsonProcessingException e) {
System.out.println("Exception: " + e.getMessage());
return;
}
}
}
输出结果:
======== 原始对象 ========
User{id=1001, name='张三', address=Address{province='内蒙古', city='鄂尔多斯市'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=520}, ReadBook{bookName='骑兵的自我修养', pageCount=1001}]}
======== 拷贝对象 ========
User{id=1001, name='张三', address=Address{province='内蒙古', city='鄂尔多斯市'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=520}, ReadBook{bookName='骑兵的自我修养', pageCount=1001}]}
======== 原始对象(修改拷贝后) ========
User{id=1001, name='张三', address=Address{province='内蒙古', city='鄂尔多斯市'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=520}, ReadBook{bookName='骑兵的自我修养', pageCount=1001}]}
======== 拷贝对象(修改拷贝后) ========
User{id=1001, name='李四', address=Address{province='内蒙古', city='包头'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=21}, ReadBook{bookName='敖包相会', pageCount=1001}]}
3. Copy Constructor(手动深拷贝)
拷贝构造器是 Java 中实现深拷贝最经典、最可控的方式,相比序列化方式更高效,且无需依赖第三方库(如 Jackson)
定义相互嵌套的拷贝类如下:
java
// 可变对象:阅读的书籍(包含可修改的属性)
class ReadBook {
private String bookName; // 书名
private Integer pageCount; // 页数(可变属性)
// 无参构造器
public ReadBook() {}
// 全参构造器
public ReadBook(String bookName, Integer pageCount) {
this.bookName = bookName;
this.pageCount = pageCount;
}
// 【核心】ReadBook的拷贝构造器(深拷贝)
public ReadBook(ReadBook original) {
this.bookName = original.bookName;
this.pageCount = original.pageCount; // Integer是不可变类型,直接赋值
}
// getter/setter(包含可变属性的setter)
public String getBookName() { return bookName; }
public void setBookName(String bookName) { this.bookName = bookName; }
public Integer getPageCount() { return pageCount; }
public void setPageCount(Integer pageCount) { this.pageCount = pageCount; }
@Override
public String toString() {
return "ReadBook{" +
"bookName='" + bookName + '\'' +
", pageCount=" + pageCount +
'}';
}
}
// 地址类:保持原有拷贝构造器逻辑
class Address {
private String province;
private String city;
public Address() {}
public Address(String province, String city) {
this.province = province;
this.city = city;
}
// Address拷贝构造器(深拷贝)
public Address(Address original) {
this.province = original.province;
this.city = original.city;
}
// getter/setter
public String getProvince() { return province; }
public void setProvince(String province) { this.province = province; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
'}';
}
}
// 用户类:hobbies改为List<ReadBook>,适配可变对象深拷贝
class User {
private Integer ID;
private String name;
private Address address;
private List<ReadBook> hobbies; // 改为可变对象集合
// 无参构造器
public User() {}
// 全参构造器(适配ReadBook集合)
public User(Integer id, String name, Address addr, List<ReadBook> hobbies) {
this.ID = id;
this.name = name;
this.address = addr;
this.hobbies = hobbies;
}
// 【核心】User拷贝构造器(全链路深拷贝)
public User(User original) {
// 基本/不可变类型直接赋值
this.ID = original.ID;
this.name = original.name;
// 嵌套Address对象:调用其拷贝构造器
if (original.address != null) {
this.address = new Address(original.address);
}
// 可变对象集合:遍历+逐个拷贝(核心修改点)
if (original.hobbies != null) {
this.hobbies = new ArrayList<>(); // 创建新集合
// 遍历原始集合,为每个ReadBook创建新实例(深拷贝)
for (ReadBook book : original.hobbies) {
this.hobbies.add(new ReadBook(book));
}
}
}
// 对外暴露深拷贝方法
public User deepClone() {
return new User(this);
}
// getter/setter(适配ReadBook集合)
public Integer getID() { return ID; }
public void setID(Integer ID) { this.ID = ID; }
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 List<ReadBook> getHobbies() { return hobbies; }
public void setHobbies(List<ReadBook> hobbies) { this.hobbies = hobbies; }
@Override
public String toString() {
return "User{" +
"id=" + ID +
", name='" + name + '\'' +
", address=" + address +
", hobbies=" + hobbies +
'}';
}
}
原始对象的 ReadBook 属性修改、集合新增元素,完全不会影响拷贝对象;
所有嵌套对象(Address、ReadBook)和集合都是全新的引用,实现了真正的全链路深拷贝;
这种方式相比序列化更可控,能精准处理每一层可变对象,且不依赖任何第三方库。
如果后续需要扩展更多层级的可变对象(如 ReadBook 中再嵌套可变对象),只需为该对象实现拷贝构造器,并在 ReadBook 的拷贝构造器中调用其拷贝构造器即可,逻辑可无限扩展且保持清晰。
测试代码如下:
java
import java.util.ArrayList;
import java.util.List;
public class ProtoType {
public static void main(String[] args) {
// 创建原始对象
Address originAddr = new Address("内蒙古", "鄂尔多斯市");
List<ReadBook> hobbies = new ArrayList<>();
hobbies.add(new ReadBook("可汗大点兵", 520));
hobbies.add(new ReadBook("骑兵的自我修养", 1001));
User originUser = new User(1001, "张三", originAddr, hobbies);
System.out.println("======== 原始对象 ========");
System.out.println(originUser);
// 执行深拷贝
User newUser01 = originUser.deepClone();
System.out.println("======== 拷贝对象 ========");
System.out.println(newUser01);
// 修改拷贝后的各项属性, 验证拷贝结果
newUser01.setName("李四");
newUser01.getAddress().setCity("包头");
newUser01.getHobbies().get(0).setPageCount(21);
newUser01.getHobbies().get(1).setBookName("敖包相会");
// 4. 验证原始对象是否被影响
System.out.println("\n======== 原始对象(修改拷贝后) ========");
System.out.println(originUser);
System.out.println("======== 拷贝对象(修改拷贝后) ========");
System.out.println(newUser01);
}
}
运行结果:
======== 原始对象 ========
User{id=1001, name='张三', address=Address{province='内蒙古', city='鄂尔多斯市'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=520}, ReadBook{bookName='骑兵的自我修养', pageCount=1001}]}
======== 拷贝对象 ========
User{id=1001, name='张三', address=Address{province='内蒙古', city='鄂尔多斯市'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=520}, ReadBook{bookName='骑兵的自我修养', pageCount=1001}]}
======== 原始对象(修改拷贝后) ========
User{id=1001, name='张三', address=Address{province='内蒙古', city='鄂尔多斯市'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=520}, ReadBook{bookName='骑兵的自我修养', pageCount=1001}]}
======== 拷贝对象(修改拷贝后) ========
User{id=1001, name='李四', address=Address{province='内蒙古', city='包头'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=21}, ReadBook{bookName='敖包相会', pageCount=1001}]}
4. Kryo(仅当 Jackson/SerializationUtils 性能不足时)
需要安装依赖
xml
<!-- Kryo 核心依赖 -->
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>kryo</artifactId>
<version>5.6.2</version>
</dependency>
<!-- Kryo 必需依赖:Objenesis(无构造器实例化) -->
<dependency>
<groupId>org.objenesis</groupId>
<artifactId>objenesis</artifactId>
<version>3.3</version>
</dependency>
<!-- Kryo 必需:日志库(解决 com.esotericsoftware.minlog.Log 缺失) -->
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>minlog</artifactId>
<version>1.3.1</version>
</dependency>
<!-- Kryo 反射实例化依赖 -->
<dependency>
<groupId>com.esotericsoftware</groupId>
<artifactId>reflectasm</artifactId>
<version>1.11.9</version>
</dependency>
<!-- ReflectASM 依赖的 ASM -->
<dependency>
<groupId>org.ow2.asm</groupId>
<artifactId>asm</artifactId>
<version>9.5</version>
</dependency>
拷贝类及Kryo的深度拷贝封装
java
/**
* Kryo深拷贝工具类
*/
class KryoCloneUtils {
// 每个线程复用一个Kryo实例(避免多线程安全问题,且无需池化依赖)
private static final ThreadLocal<Kryo> KRYO_THREAD_LOCAL = ThreadLocal.withInitial(() -> {
Kryo kryo = new Kryo();
kryo.setRegistrationRequired(false);
kryo.setReferences(true);
return kryo;
});
/**
* 核心深拷贝方法(ThreadLocal复用Kryo实例)
*/
@SuppressWarnings("unchecked")
public static <T> T deepClone(T obj) {
if (obj == null) return null;
Kryo kryo = KRYO_THREAD_LOCAL.get();
ByteArrayOutputStream bos = null;
Output output = null;
Input input = null;
try {
// 1. 序列化对象
bos = new ByteArrayOutputStream();
output = new Output(bos);
kryo.writeClassAndObject(output, obj);
output.flush();
// 2. 反序列化生成拷贝对象
input = new Input(new ByteArrayInputStream(bos.toByteArray()));
return (T) kryo.readClassAndObject(input);
} catch (Exception e) {
throw new RuntimeException("Kryo深拷贝失败", e);
} finally {
// 关闭流 + 移除ThreadLocal(避免内存泄漏)
if (input != null) input.close();
if (output != null) output.close();
KRYO_THREAD_LOCAL.remove();
}
}
}
// 可变对象:阅读的书籍(包含可修改的属性)
class ReadBook {
private String bookName; // 书名
private Integer pageCount; // 页数(可变属性)
// 无参构造器(Kryo反序列化必需)
public ReadBook() {}
// 全参构造器
public ReadBook(String bookName, Integer pageCount) {
this.bookName = bookName;
this.pageCount = pageCount;
}
// getter/setter(包含可变属性的setter)
public String getBookName() { return bookName; }
public void setBookName(String bookName) { this.bookName = bookName; }
public Integer getPageCount() { return pageCount; }
public void setPageCount(Integer pageCount) { this.pageCount = pageCount; }
@Override
public String toString() {
return "ReadBook{" +
"bookName='" + bookName + '\'' +
", pageCount=" + pageCount +
'}';
}
}
// 地址类:保持原有拷贝构造器逻辑
class Address {
private String province;
private String city;
// 无参构造器(Kryo反序列化必需)
public Address() {}
// 全参构造器
public Address(String province, String city) {
this.province = province;
this.city = city;
}
// getter/setter
public String getProvince() { return province; }
public void setProvince(String province) { this.province = province; }
public String getCity() { return city; }
public void setCity(String city) { this.city = city; }
@Override
public String toString() {
return "Address{" +
"province='" + province + '\'' +
", city='" + city + '\'' +
'}';
}
}
// 用户类:hobbies改为List<ReadBook>,适配可变对象深拷贝
class User {
private Integer ID;
private String name;
private Address address;
private List<ReadBook> hobbies; // 改为可变对象集合
// 无参构造器
public User() {}
// 全参构造器(适配ReadBook集合)
public User(Integer id, String name, Address addr, List<ReadBook> hobbies) {
this.ID = id;
this.name = name;
this.address = addr;
this.hobbies = hobbies;
}
// 对外暴露深拷贝方法
public User deepClone() {
return KryoCloneUtils.deepClone(this);
}
// getter/setter(适配ReadBook集合)
public Integer getID() { return ID; }
public void setID(Integer ID) { this.ID = ID; }
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 List<ReadBook> getHobbies() { return hobbies; }
public void setHobbies(List<ReadBook> hobbies) { this.hobbies = hobbies; }
@Override
public String toString() {
return "User{" +
"id=" + ID +
", name='" + name + '\'' +
", address=" + address +
", hobbies=" + hobbies +
'}';
}
}
测试代码:
java
import com.esotericsoftware.kryo.Kryo;
import com.esotericsoftware.kryo.io.Input;
import com.esotericsoftware.kryo.io.Output;
import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.util.ArrayList;
import java.util.List;
public class ProtoType {
public static void main(String[] args) {
// 创建原始对象
Address originAddr = new Address("内蒙古", "鄂尔多斯市");
List<ReadBook> hobbies = new ArrayList<>();
hobbies.add(new ReadBook("可汗大点兵", 520));
hobbies.add(new ReadBook("骑兵的自我修养", 1001));
User originUser = new User(1001, "张三", originAddr, hobbies);
System.out.println("======== 原始对象 ========");
System.out.println(originUser);
// 执行深拷贝
User newUser01 = originUser.deepClone();
System.out.println("======== 拷贝对象 ========");
System.out.println(newUser01);
// 修改拷贝后的各项属性, 验证拷贝结果
newUser01.setName("李四");
newUser01.getAddress().setCity("包头");
newUser01.getHobbies().get(0).setPageCount(21);
newUser01.getHobbies().get(1).setBookName("敖包相会");
// 4. 验证原始对象是否被影响
System.out.println("\n======== 原始对象(修改拷贝后) ========");
System.out.println(originUser);
System.out.println("======== 拷贝对象(修改拷贝后) ========");
System.out.println(newUser01);
}
}
运行结果:
======== 原始对象 ========
User{id=1001, name='张三', address=Address{province='内蒙古', city='鄂尔多斯市'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=520}, ReadBook{bookName='骑兵的自我修养', pageCount=1001}]}
WARNING: An illegal reflective access operation has occurred
WARNING: Illegal reflective access by com.esotericsoftware.reflectasm.AccessClassLoader (file:/C:/Users/xuegu/.m2/repository/com/esotericsoftware/reflectasm/1.11.9/reflectasm-1.11.9.jar) to method java.lang.ClassLoader.defineClass(java.lang.String,byte[],int,int,java.security.ProtectionDomain)
WARNING: Please consider reporting this to the maintainers of com.esotericsoftware.reflectasm.AccessClassLoader
WARNING: Use --illegal-access=warn to enable warnings of further illegal reflective access operations
WARNING: All illegal access operations will be denied in a future release
======== 拷贝对象 ========
User{id=1001, name='张三', address=Address{province='内蒙古', city='鄂尔多斯市'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=520}, ReadBook{bookName='骑兵的自我修养', pageCount=1001}]}
======== 原始对象(修改拷贝后) ========
User{id=1001, name='张三', address=Address{province='内蒙古', city='鄂尔多斯市'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=520}, ReadBook{bookName='骑兵的自我修养', pageCount=1001}]}
======== 拷贝对象(修改拷贝后) ========
User{id=1001, name='李四', address=Address{province='内蒙古', city='包头'}, hobbies=[ReadBook{bookName='可汗大点兵', pageCount=21}, ReadBook{bookName='敖包相会', pageCount=1001}]}
报了很多警告, 暂时没能力解决, 待日后回来搞定, 但是这里所有的代码是正确能够运行的.
(二)浅拷贝及跨类拷贝场景
1. Spring BeanUtils(简单场景)
暂不举例
2. MapStruct(复杂 / 高性能场景)
#暂不举例
Lombok @With
暂不举例
Builder + toBuilder()
暂不举例