二十三种设计模式(四)--原型模式

原型模式

原型模式实现的操作就是基于原型实例, 创建一个新的对象.

一般我们获取一个对象的复制版, 就是直接new一个新的对象, 传入相同的参数.

但是, 当构造过程过于复杂,比如需要大量计算

或者构造过程依赖外部资源, 比如要连接好数据库, 或者要读写外部文件

此时获取一个相同的类对象副本就过于复杂.

因此我们对这种复杂的类的封装时, 要加入一个便于复制的方法接口.

Java自身带的Cloneable接口以及Java自带的clone方法有很多不安全因素, 容易因判断错深浅拷贝而导致bug, 同时也因直接的复制内存破坏类的封装性.

Java中实现原型模式的方法推荐方式:

(一)深拷贝场景

1. Apache SerializationUtils(有 Serializable)

Apache Commons Lang 的 SerializationUtils 基于序列化 / 反序列化实现对象拷贝,本质是深拷贝(前提是所有成员变量都实现 Serializable)

注意事项:

  1. Serializable 是标记接口,无需实现任何方法,但建议显式声明 serialVersionUID 避免序列化兼容问题;
  2. 若成员变量是 transient(瞬态),序列化时会被忽略,拷贝后该字段为默认值(如 null/0);
  3. 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 对象,需要通过「反射」创建对象实例,默认逻辑是:

  1. 先通过反射调用类的 无参构造器 创建一个空对象(new User() / new Address());
  2. 再通过反射调用 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()

暂不举例

相关推荐
沐浴露z1 小时前
详解Java ArrayList
java·开发语言·哈希算法
第二只羽毛1 小时前
单例模式的初识
java·大数据·数据仓库·单例模式
4***g8941 小时前
Java进阶-SpringCloud设计模式-工厂模式的设计与详解
java·spring cloud·设计模式
__万波__1 小时前
二十三种设计模式(五)--建造者模式
java·设计模式·建造者模式
北郭guo1 小时前
Java设计模式 【理论+代码实现】 让你从小白到大佬的蜕变
java·开发语言·设计模式
计算机徐师兄1 小时前
Java基于微信小程序的贝壳活动助手【附源码、文档说明】
java·微信小程序·贝壳活动助手·贝壳活动助手小程序·贝壳活动助手微信小程序·java贝壳活动助手小程序·java贝壳活动助手微信小程序
Gavin在路上1 小时前
架构设计之COLA架构
java·数据库·架构
MediaTea1 小时前
Python 库手册:gc 垃圾回收
java·开发语言·jvm·python·算法
碎像1 小时前
阿里云 ARMS 应用实时监控服务
java·阿里云·云计算