深拷贝与Serializable简介

本文介绍了一种利用Java Serializable接口实现深拷贝的方法,并通过示例代码详细解释了其实现过程及验证步骤。

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

上次我们说了Copy Constructor与clone()方法。谈到用拷贝构造函数和clone()方法来实现深拷贝会很麻烦。
那么有没有什么简单的方法来实现深拷贝呢?答案是有的,使用Java Serializable来实现深拷贝。

0. 数据类模型

什么是Serializable?我们来看下代码。

public interface Serializable {
}

和之前的Cloneable是一个样子,与其说是一个接口,更像是一个属性。
我们建立一个嵌套深度为3的数据类。
注:这不是一个很好的面向对象的封装方式。此处只为缩减代码量。正式编程中请不要随便暴露类变量。

public class DataClass implements Serializable{
    A a;
    double valueC;

    public DataClass(){
        a = new A();
        valueC = 1.05;
    }

    public DataClass(int valueA, float valueB, double valueC){
      this.valueC = valueC;
      a = new A(valueA, valueB);
    }

    @Override
    public String toString(){
        StringBuilder sb = new StringBuilder();
        sb.append("a = ").append(a.valueA).append("\n");
        sb.append("b = ").append(a.b.valueB).append("\n");
        sb.append("c = ").append(valueC).append("\n");
        return sb.toString();
    }
}

其中,A类声明如下。

public class A implements Serializable {
    int valueA;
    B b;

    public A(){
        valueA = 100;
    }

    public A(int valueA, float valueB){
        this.valueA = valueA;
        b = new B(valueB);
    }
    @Override
    public String toString(){
        StringBuilder sb = new StringBuilder();
        sb.append("a = ").append(valueA).append("\n");
        sb.append("b = ").append(b.valueB).append("\n");
        return sb.toString();
    }
}

B类声明如下。

public class B implements Serializable {
    float valueB;

    public B(){
        valueB = 10f;
    }

    public B(float valueB){
        this.valueB = valueB;
    }
}

1. 深拷贝的实现

核心思想是用ObjectOutputStream来实现类的序列化;用ObjectInputStream来实现类的反序列化。
承载输出数据,以及接受的输入数据可以是:来自内存(ByteArrayOutputStream),来自文件(FileOutputStream),来自网络(Socket.getOutputStream())等。
因为深拷贝,我们写到内存里就可以,不需要对硬盘进行访问。

我们对2个DataClass和1个A类进行深拷贝。
实现代码如下。

    DataClass serial1 = new DataClass(1,1.1f,1.2);
    DataClass serial2 = new DataClass(2,2.1f,2.2);
    A serial3 = new A(3,3.3f);

    //Serialize
    ByteArrayOutputStream byteOut = new ByteArrayOutputStream();
    ObjectOutputStream objectOut = new ObjectOutputStream(byteOut);
    objectOut.writeObject(serial1);
    objectOut.writeObject(serial2);
    objectOut.writeObject(serial3);
    objectOut.close();

    byte[] buffer = byteOut.toByteArray();


    //Deserialize
    ByteArrayInputStream byteIn = new ByteArrayInputStream(buffer);
    ObjectInputStream objectIn = new ObjectInputStream(byteIn);

    DataClass deSerial1 = (DataClass) objectIn.readObject();
    DataClass deSerial2 = (DataClass) objectIn.readObject();
    A deSerial3 = (A) objectIn.readObject();

    System.out.println("Serialization:");
    System.out.println("serial1:");
    System.out.println(serial1);
    System.out.println("serial2:");
    System.out.println(serial2);
    System.out.println("serial3:");
    System.out.println(serial3);


    System.out.println("Deserialization:");
    System.out.println("de-serial1");
    System.out.println(deSerial1);
    System.out.println("de-serial2");
    System.out.println(deSerial2);
    System.out.println("de-serial3");
    System.out.println(deSerial3);

得到结果如下:

Serialization:
serial1:
a = 1
b = 1.1
c = 1.2

serial2:
a = 2
b = 2.1
c = 2.2

serial3:
a = 3
b = 3.3

Deserialization:
de-serial1
a = 1
b = 1.1
c = 1.2

de-serial2
a = 2
b = 2.1
c = 2.2

de-serial3
a = 3
b = 3.3

进一步验证是否是深拷贝,我们进行如下修改。

    serial1.a.b.valueB = 99.9f;
    System.out.println("serial1:");
    System.out.println(serial1);
    System.out.println("de-serial1");
    System.out.println(deSerial1);

得到结果如下。

serial1:
a = 1
b = 99.9
c = 1.2

de-serial1
a = 1
b = 1.1
c = 1.2

可知,确实为深拷贝。

如果一个类的某些变量不想被序列化传递,可以声明为transient. 例如:

transient A a;

这样a这个变量就不会被序列化传递。
与此同时,带来的问题是,在反序列化的时候,对于一个类会抛出空指针异常(NullPointerException). 对于8大基础数据类型,则会被初始化为初始值(0, false等)

2. Serializable简介

你以为这就是Serializable的作用?不,这只是其冰山一角的功能罢了。Serializable最大的作用是可以将数据序列化后通过网络传输。相当于Java内建的XML, json.
以DataClass(1, 1.1f, 1.2)为例,其序列化格式如下(从左到右,从上到下):

DataClass8-byte version numberh0
2Adouble
A(1, 1.1f)1.2h1

其中h0和h1是句柄。

Serializable的其他用途我们下次再聊。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值