java对象的序列化与反序列化(Serializable)

2018-12-26  本文已影响0人  漫不经心v
先看看概念介绍:
应用场景
让我们用代码加深理解吧

一、这是一个要被序列化和反序列化的类:

/**
 *需要传输或持久化的java对象,实现Serializable接口
 *
 */
import java.io.Serializable;

public class SerializableBean implements Serializable {
    
    private static final long serialVersionUID = 1L;

    private String name;
    private String param;
    public String getName() {
        return name;
    }
    public void setName(String name) {
        this.name = name;
    }
    public String getParam() {
        return param;
    }
    public void setParam(String param) {
        this.param = param;
    }
}

二、这是一个把SerializableBean序列化和反序列化的类:

/**
 *
 *把SerializableBean序列化和反序列化的类
 */
import java.io.File;
import java.io.FileInputStream;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectInputStream;
import java.io.ObjectOutputStream;

public class SerializableTest {

    public static void main(String[] args) {
        
        String path = "D://SAFile";
        // 实例化SerializableBean,设置值
        SerializableBean sa = new SerializableBean();
        sa.setName("Cyf");
        sa.setParam("test");

        // 写入文件
        try {
            ObjectOutputStream oos = new ObjectOutputStream(
                    new FileOutputStream(path));
            oos.writeObject(sa);
        } catch (IOException e) {
            e.printStackTrace();
        }
        
        //读取文件输出
        File file = new File(path);
        FileInputStream fis;
        try {
            fis = new FileInputStream(file);
            ObjectInputStream ois = new ObjectInputStream(fis);
            SerializableBean invsa = (SerializableBean) ois.readObject();
            System.out.print(invsa.getClass() + " " 
                    + invsa.getName() + " " 
                    + invsa.getParam());
        } catch (IOException | ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

}

1.第一段代码中,首先我们定义了一个实现Serializable接口的SerializableBean类,这个类中有name和param属性。
2.第二段代码中,分为两部分:一部分是实例化SerializableBean类,并设置属性值,然后把这个类序列化持久化到D盘中;另一部分是反序列化并输出这个对象的属性值。

序列化和反序列化的扩展点
1.serialVersionUID的值

需要被序列化和反序列化的对象设置一个serialVersionUID值:

private static final long serialVersionUID = 1L;

这个值就如同序列化和反序列化之间的版本约定。举个例子:如果我先把反序列化部分代码屏蔽,在序列化的时候设置SerializableBean类的serialVersionUID值为1L,然后屏蔽序列化部分代码,在反序列化的时候设置SerializableBean类的serialVersionUID值为2L,就会报错:

java.io.InvalidClassException: 
local class incompatible: stream classdesc serialVersionUID = 1,
local class serialVersionUID = 2
2.transient

若我们在SerializableBean类中增加一个用transient修饰的属性:

    private transient String constant;
    public String getConstant() {
        return constant;
    }
    public void setConstant(String constant) {
        this.constant = constant;
    }

在序列化之前设置constant值

    sa.setConstant("CONSTANT");

在反序列化部分代码中修改输出:

     System.out.print(invsa.getClass() + " " 
                    + invsa.getName() + " " 
                    + invsa.getParam() + " "
                    + invsa.getConstant());

输出结果:

class com.test.SerializableBean Cyf test null

constant的值为null。
可以得出用transient修饰的属性将不被序列化。

3.Externalizable

Externalizable继承Serializable,扩展了writeExternal(),readExternal()这两个方法。
若我们直接把SerializableBean类实现接口改成Externalizable,序列化和反序列化之后的输出是:

    class com.test.SerializableBean null null null

我们发现,之前的三个属性的值都没被序列化。
那么如何来设置属性值呢?
这时候就要用到writeExternal(),readExternal()这两个方法了:

    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(name);
        out.writeObject(param);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        name = (String) in.readObject();
        param = (String) in.readObject();
    }

再次输出:

    class com.test.ExternalizableBean Cyf test

序列化和反序列化End。

上一篇下一篇

猜你喜欢

热点阅读