java序列化

什么是java序列化与反序列化

  • 序列化:把java对象通过某种方式写入磁盘,或者传输给其他网络节点。即将对象转为二进制的过程。
  • 反序列化:把磁盘中的文件,或者网络节点的数据通过某种方式转为java对象。即将二进制转为对象。

java序列化的使用场景

通过上面序列化的定义,可以初步了解序列化的使用场景。

  • 将内存中的数据保存到磁盘或者数据库中。
  • 需要在网络中传输对象。
  • 想通过RMI传输对象。

java序列化实例

下面直接上代码,通过代码实例学习如何实现序列化。

创建实体

为了深入理解实现序列化与反序列化,首先创建几个实体。
User.java、Person.java、OtherInfo.java,他们的关系是User.java中引用了OtherInfo.java,User.java继承了Person.java。三个实体都有get/set/toString方法,方便查看测试效果。

为何创建创建这三个实体呢?

  • 测试是否能序列化父类的数据
  • 测试是否能序列化引用类型的数据

代码如下:

User.java

package org.ludk.serializable;

import java.io.Serializable;

/**
 * @author ludengke
 * @title: User
 * @projectName springcloud-demo
 * @description: TODO
 * @date 2021/10/2420:14
 */
public class User extends Person  {
    private String name;
    private int age;
    private OtherInfo otherInfo;

    public User(String name, int age, OtherInfo otherInfo) {
        this.name = name;
        this.age = age;
        this.otherInfo = otherInfo;
    }

    @Override
    public String toString() {
        return "User{" +
                "name='" + name + '\'' +
                ", age=" + age +
                ", otherInfo=" + otherInfo +
                '}'+
                super.toString();
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public OtherInfo getOtherInfo() {
        return otherInfo;
    }

    public void setOtherInfo(OtherInfo otherInfo) {
        this.otherInfo = otherInfo;
    }
}

OtherInfo.java

package org.ludk.serializable;

import java.io.Serializable;

/**
 * @author ludengke
 * @title: OtherInfo
 * @projectName springcloud-demo
 * @description: TODO
 * @date 2021/10/2420:15
 */
public class OtherInfo  {
    private String ph;
    private String address;

    public OtherInfo(String ph, String address) {
        this.ph = ph;
        this.address = address;
    }

    @Override
    public String toString() {
        return "OtherInfo{" +
                "ph='" + ph + '\'' +
                ", address='" + address + '\'' +
                '}';
    }

    public String getPh() {
        return ph;
    }

    public void setPh(String ph) {
        this.ph = ph;
    }

    public String getAddress() {
        return address;
    }

    public void setAddress(String address) {
        this.address = address;
    }
}

Person.java

package org.ludk.serializable;

import java.io.Serializable;

/**
 * @author ludengke
 * @title: Person
 * @projectName springcloud-demo
 * @description: TODO
 * @date 2021/10/2420:18
 */
public class Person  {
    private String head;
    private String body;

    @Override
    public String toString() {
        return "Person{" +
                "head='" + head + '\'' +
                ", body='" + body + '\'' +
                '}';
    }

    public String getHead() {
        return head;
    }

    public void setHead(String head) {
        this.head = head;
    }

    public String getBody() {
        return body;
    }

    public void setBody(String body) {
        this.body = body;
    }
}

java序列化与反序列化工具类

SerializableUtil.java

package org.ludk.serializable;

import java.io.*;

/**
 * @author ludengke
 * @title: SerializableUtil
 * @projectName springcloud-demo
 * @description: 克隆的工具类
 * @date 2021/10/2420:24
 */
public class SerializableUtil {
    /**
    *@Description 保存对象,序列化
    *@Param [object]
    *@Return void
    *@Author ludengke
    *@Date 2021/10/24
    *@Time 20:29
    */
    public static void saveObject(Object object){
        ObjectOutputStream objectOutputStream=null;
        FileOutputStream fileOutputStream=null;
        try {
            fileOutputStream=new FileOutputStream("D:\\work\\test\\serializable\\writeToFile.txt");
            objectOutputStream=new ObjectOutputStream(fileOutputStream);
            objectOutputStream.writeObject(object);
            objectOutputStream.flush();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }finally {
            try {
                objectOutputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
    /**
    *@Description 读对象,反序列化
    *@Param []
    *@Return java.lang.Object
    *@Author ludengke
    *@Date 2021/10/24
    *@Time 20:36
    */
    public static Object readObject(){
        ObjectInputStream objectInputStream=null;
        FileInputStream fileInputStream=null;
        try {
            fileInputStream=new FileInputStream("D:\\work\\test\\serializable\\writeToFile.txt");
            objectInputStream=new ObjectInputStream(fileInputStream);
            return objectInputStream.readObject();
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }finally {
            try {
                objectInputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return null;
    } 
}

测试类

TestSerializable.java

package org.ludk.serializable;

/**
 * @author ludengke
 * @title: TestSerializable
 * @projectName springcloud-demo
 * @description: TODO
 * @date 2021/10/2420:19
 */
public class TestSerializable {

    public static void main(String[] args) {
        User user=new User("卢**",35,new OtherInfo("1834156****","北京海淀"));
        user.setHead("大头");
        user.setBody("小身体");
        //打印序列化前的对象
        System.out.println(user);
        //序列化
        SerializableUtil.saveObject(user);
        //反序列化
        User readFromFile=(User) SerializableUtil.readObject();
        //打印通过反序列化生成的对象
        System.out.println(readFromFile);
    }
}

测试与修正的过程

  1. 运行TestSerializable.java的main方法,结果如下:
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=51808:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\target\classes org.ludk.serializable.TestSerializable
User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'}
java.io.NotSerializableException: org.ludk.serializable.User
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
	at org.ludk.serializable.SerializableUtil.saveObject(SerializableUtil.java:27)
	at org.ludk.serializable.TestSerializable.main(TestSerializable.java:17)
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: org.ludk.serializable.User
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1631)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:464)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
	at org.ludk.serializable.SerializableUtil.readObject(SerializableUtil.java:55)
	at org.ludk.serializable.TestSerializable.main(TestSerializable.java:18)
Caused by: java.io.NotSerializableException: org.ludk.serializable.User
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
	at org.ludk.serializable.SerializableUtil.saveObject(SerializableUtil.java:27)
	at org.ludk.serializable.TestSerializable.main(TestSerializable.java:17)
null

Process finished with exit code 0

java.io.NotSerializableException: org.ludk.serializable.User的意思很明显,org.ludk.serializable.User不能被实例化。

结论一:被序列化的对象实体需要实现java.io.Serializable接口,否则会抛NotSerializableException异常

所以让org.ludk.serializable.User实现serializable接口,被调整的部分代码如下:

public class User extends Person implements Serializable {

  1. 再次跑测试类,结果如下:
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=52041:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\target\classes org.ludk.serializable.TestSerializable
User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'}
java.io.NotSerializableException: org.ludk.serializable.OtherInfo
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
	at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
	at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
	at org.ludk.serializable.SerializableUtil.saveObject(SerializableUtil.java:27)
	at org.ludk.serializable.TestSerializable.main(TestSerializable.java:17)
java.io.WriteAbortedException: writing aborted; java.io.NotSerializableException: org.ludk.serializable.OtherInfo
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1631)
	at java.io.ObjectInputStream.defaultReadFields(ObjectInputStream.java:2341)
	at java.io.ObjectInputStream.readSerialData(ObjectInputStream.java:2265)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2123)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1624)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:464)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:422)
	at org.ludk.serializable.SerializableUtil.readObject(SerializableUtil.java:55)
	at org.ludk.serializable.TestSerializable.main(TestSerializable.java:18)
Caused by: java.io.NotSerializableException: org.ludk.serializable.OtherInfo
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1184)
	at java.io.ObjectOutputStream.defaultWriteFields(ObjectOutputStream.java:1548)
	at java.io.ObjectOutputStream.writeSerialData(ObjectOutputStream.java:1509)
	at java.io.ObjectOutputStream.writeOrdinaryObject(ObjectOutputStream.java:1432)
	at java.io.ObjectOutputStream.writeObject0(ObjectOutputStream.java:1178)
	at java.io.ObjectOutputStream.writeObject(ObjectOutputStream.java:348)
	at org.ludk.serializable.SerializableUtil.saveObject(SerializableUtil.java:27)
	at org.ludk.serializable.TestSerializable.main(TestSerializable.java:17)
null

Process finished with exit code 0

java.io.NotSerializableException: org.ludk.serializable.OtherInfo
这段错误说明OtherInfo也要实现serializable接口。

结论二:引用对象的实体类也需要实现java.io.Serializable接口,否则抛NotSerializableException异常。

调整的部分代码如下:

public class OtherInfo  implements Serializable{

  1. 再次跑测试类,结果如下:
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=52382:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\target\classes org.ludk.serializable.TestSerializable
User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'}
User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='null', body='null'}

Process finished with exit code 0

这次不抛异常了,但是父类Person.java的属性没有被序列化,head和body为空。

结论三:父类也要实现java.io.Serializable接口,否则父类的属性不会被序列化。

调整的部分代码如下:

public class Person  implements Serializable{

  1. 再次跑测试类,结果如下:
D:\work\java\bin\java.exe "-javaagent:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\lib\idea_rt.jar=52500:C:\Program Files\JetBrains\IntelliJ IDEA 2019.3.3\bin" -Dfile.encoding=UTF-8 -classpath D:\work\java\jre\lib\charsets.jar;D:\work\java\jre\lib\deploy.jar;D:\work\java\jre\lib\ext\access-bridge-64.jar;D:\work\java\jre\lib\ext\cldrdata.jar;D:\work\java\jre\lib\ext\dnsns.jar;D:\work\java\jre\lib\ext\jaccess.jar;D:\work\java\jre\lib\ext\jfxrt.jar;D:\work\java\jre\lib\ext\localedata.jar;D:\work\java\jre\lib\ext\nashorn.jar;D:\work\java\jre\lib\ext\sunec.jar;D:\work\java\jre\lib\ext\sunjce_provider.jar;D:\work\java\jre\lib\ext\sunmscapi.jar;D:\work\java\jre\lib\ext\sunpkcs11.jar;D:\work\java\jre\lib\ext\zipfs.jar;D:\work\java\jre\lib\javaws.jar;D:\work\java\jre\lib\jce.jar;D:\work\java\jre\lib\jfr.jar;D:\work\java\jre\lib\jfxswt.jar;D:\work\java\jre\lib\jsse.jar;D:\work\java\jre\lib\management-agent.jar;D:\work\java\jre\lib\plugin.jar;D:\work\java\jre\lib\resources.jar;D:\work\java\jre\lib\rt.jar;D:\work\springcloud-demo\target\classes org.ludk.serializable.TestSerializable
User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'}
User{name='卢**', age=35, otherInfo=OtherInfo{ph='1834156****', address='北京海淀'}}Person{head='大头', body='小身体'}

Process finished with exit code 0

完美了。
听说静态变量不会被序列化( static,transient),我就不试了。
结论四:静态变量不会被序列化( static,transient)

序列化ID

序列化时一般会加入下面的代码(我没加):

 private static final long serialVersionUID = 1L;

它决定着是否能够成功反序列化!

java的序列化机制是通过判断运行时类的serialVersionUID来验证版本一致性的,在进行反序列化时,JVM会把传进来的字节流中的serialVersionUID与本地实体类中的serialVersionUID进行比较,如果相同则认为是一致的,便可以进行反序列化,否则就会报序列化版本不一致的异常。

因为我测试的时候是用一个实体序列化和反序列化,所以看不出效果。

java序列化总结

  • 被序列化的对象实体需要实现java.io.Serializable接口,否则会抛NotSerializableException异常。

  • 引用对象的实体类也需要实现java.io.Serializable接口,否则抛NotSerializableException异常

  • 父类也要实现java.io.Serializable接口,否则父类的属性不会被序列化。

  • 静态变量不会被序列化( static,transient)

  • 序列化ID应自己写,尽量不自动生成,因为序列化与反序列化的序列化ID应该保持一致

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值