Cloneable、Serializable接口克隆对象

本文介绍了两种克隆对象的方法:实现Cloneable接口重写clone()方法及利用Serializable接口通过序列化和反序列化实现深度克隆。后者不仅实现了深度克隆,还能够通过泛型限定检查对象是否支持序列化。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

使用Cloneable、Serializable接口克隆对象

1). 实现Cloneable接口并重写Object类中的clone()方法;
2). 实现Serializable接口,通过对象的序列化和反序列化实现克隆,可以实现真正的深度克隆,代码如下。

import java.io.ByteArrayInputStream;
import java.io.ByteArrayOutputStream;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class MyUtil {

    private MyUtil() {
        throw new AssertionError();
    }

    public static <T> T clone(T obj) throws Exception {
        ByteArrayOutputStream bout = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(bout);
        oos.writeObject(obj);

        ByteArrayInputStream bin = new ByteArrayInputStream(bout.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bin);
        return (T) ois.readObject();

        // 说明:调用ByteArrayInputStream或ByteArrayOutputStream对象的close方法没有任何意义
        // 这两个基于内存的流只要垃圾回收器清理对象就能够释放资源,这一点不同于对外部资源(如文件流)的释放
import java.io.Serializable;
class Person implements Serializable {
    private String name;    // 姓名
    private int age;        // 年龄
    private Team tean;        // 团队
    //get、set省略
    }
class Team implements Serializable {
    private String tname;       // 团队名称
    private int mumber;       // 人数
    //set 、get省略
    }
class CloneTest {

    public static void main(String[] args) {
        try {
            Person p1 = new Person("Hao LUO", 33, new Team("Rockets", 30));
            Person p2 = MyUtil.clone(p1);   // 深度克隆
            p2.getTeam().setTname("GSW");
            // 修改克隆的Person对象p2关联的团队对象的名称属性
            // 原来的Person对象p1关联的队名不会受到任何影响
            // 因为在克隆Person对象时其关联的团队对象也被克隆了
            System.out.println(p1);
        } catch (Exception e) {
            e.printStackTrace();
        }

注意:基于序列化和反序列化实现的克隆不仅仅是深度克隆,更重要的是通过泛型限定,可以检查出要克隆的对象是否支持序列化,这项检查是编译器完成的,不是在运行时抛出异常,这种是方案明显优于使用Object类的clone方法克隆对象。让问题在编译的时候暴露出来总是优于把问题留到运行时。

<think>在Java中,`Cloneable`接口是一个标记接口(marker interface),它没有定义任何方法。实现此接口的类允许使用`Object.clone()`方法创建该对象的副本(即克隆)。如果一个类没有实现`Cloneable`接口,调用其`clone()`方法会抛出`CloneNotSupportedException`异常。 ### 关键点: 1. **标记接口作用**:`Cloneable`接口仅用于指示JVM该对象可以被克隆。它本身没有方法,属于一种约定。 2. **与`Object.clone()`的关系**: - `Object`类中有一个受保护的`clone()`方法(`protected native Object clone() throws CloneNotSupportedException;`)。 - 要使用`clone()`方法,类必须: - 实现`Cloneable`接口(否则抛异常)。 - 重写`clone()`方法并将其访问修饰符改为`public`(否则外部无法调用)。 3. **浅拷贝与深拷贝**: - 默认的`clone()`方法是浅拷贝(shallow copy):复制对象本身及其基本类型字段,但引用类型字段只复制引用(不复制引用的对象)。 - 如需深拷贝(deep copy),需在重写的`clone()`方法中手动复制引用对象。 4. **重写`clone()`的示例**: ```java public class Person implements Cloneable { private String name; private int age; // 构造方法、getter/setter等省略... @Override public Object clone() throws CloneNotSupportedException { return super.clone(); // 默认浅拷贝 } } ``` ### 注意事项: - **慎用克隆**:深拷贝实现复杂(尤其嵌套引用多时),且可能破坏单例模式。推荐使用拷贝构造器或工具类(如Apache Commons的`SerializationUtils`)实现深拷贝。 - **数组默认支持克隆**:Java数组实现了`Cloneable`,可直接调用`clone()`。 --- §§相关问题§§ 1. Java中除了`Cloneable`,还有哪些常见的标记接口(marker interface)? 2. 如何实现深拷贝(deep copy)?除了重写`clone()`方法,还有哪些替代方案? 3. 为什么`Object.clone()`方法是受保护的(protected)?直接调用它有什么限制? 4. 浅拷贝和深拷贝在实际应用中可能引发哪些问题(例如:多线程环境、对象共享)? 5. 实现`Cloneable`接口与使用序列化(Serializable)进行对象复制相比,各有什么优缺点?</think>### `Cloneable` 接口介绍 `Cloneable` 是 Java 中的一个标记接口(Marker Interface),位于 `java.lang` 包中。它没有任何方法定义,仅用于向 JVM 表明**允许对该类对象进行克隆操作**。若类未实现 `Cloneable` 却调用 `clone()` 方法,会抛出 `CloneNotSupportedException`。 --- ### 核心机制 1. **与 `Object.clone()` 的关系** - `Object.clone()` 是 Java 所有类的默认克隆方法(`protected native` 实现)。 - 若类未显式重写 `clone()` 且未实现 `Cloneable`,调用 `clone()` 会抛出异常。 - 合法克隆必须同时满足: ✅ 类实现 `Cloneable` 接口 ✅ 重写 `clone()` 方法并改为 `public` 访问权限 2. **浅拷贝(Shallow Copy)** 默认的 `Object.clone()` 执行浅拷贝: - 复制对象本身的值类型字段 - 复制引用类型字段的**地址**(新旧对象共享引用对象) ```java @Override public Object clone() throws CloneNotSupportedException { return super.clone(); // 默认浅拷贝 } ``` 3. **深拷贝(Deep Copy)实现** 需手动重写 `clone()`,递归复制引用对象: ```java class Department implements Cloneable { String name; @Override protected Object clone() throws CloneNotSupportedException { return super.clone(); } } class Employee implements Cloneable { String name; Department dept; // 引用对象 @Override public Object clone() throws CloneNotSupportedException { Employee cloned = (Employee) super.clone(); cloned.dept = (Department) dept.clone(); // 手动深拷贝 return cloned; } } ``` --- ### 注意事项 1. **数组默认支持克隆** Java 数组隐式实现 `Cloneable`,可直接调用 `clone()`: ```java int[] arr = {1, 2, 3}; int[] copy = arr.clone(); // 合法操作 ``` 2. **替代方案** - **拷贝构造器**:`public Employee(Employee src)` - **工厂方法**:`Employee.fromPrototype(Employee src)` - **序列化工具**:Apache Commons Lang 的 `SerializationUtils.clone()` 3. **设计缺陷** - 未强制重写 `clone()`,易导致误用 - 浅拷贝可能引发数据不一致(需谨慎处理可变引用对象) ---
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值