写于:2018-12-10 08:52:37

# 什么是序列化

程序存在的意义就是进行数据的计算与传输,在我们的网络架构中只能识别二进制和字节码,而不能识别java对象。 序列化就是将无法识别的java对象转化为二进制和字节码的一种机制。

通过一定的规则将 java对象,包括数据和数据类型转换成二进制和字节码 称为序列化。 将二进制和字节码还原成 java对象的过程就称为反序列化

# 什么是 serialVersionUID

1、每一个实现序列化接口 Serializable 的java 对象,都有一个 serialVersionUID。

2、serialVersionUID 是唯一的,相当于 java对象的唯一身份标识

3、如果没有显示声明,java 对象 serialVersionUID 会根据类中的数据、结构生成。也就是说,一旦修改了 java 对象,serialVersionUID 也会不同

4、为了保证,在对java 对象添加一个方法,或者修改某个数据 不会发生无法反序列化的结果,这是就要指定 serialVersionUID 。保证 反序列化的正常执行。

# java 原生 序列化机制

# 测试对象:Money.java

public class Money implements Serializable {
    private static final long serialVersionUID = 3633493362137985111L;
    private BigDecimal value;

    public void setValue(BigDecimal value) {
        this.value = value;
    }

    @Override
    public String toString() {
        return "Money{" +
                "value=" + value +
                '}';
    }
}

# 测试类:Demo.java

public class Demo {
     private static final String fileName = System.getProperty("user.dir") + File.separator + "a.txt";

    public static void main(String[] args) {
        serialize();
        deserialization();
    }

    /**
     * 序列化数据测试
     * @return
     */
    public static Money javaObject(){
        Money money = new Money();
        money.setValue(BigDecimal.valueOf(100));
        return money;
    }

    /**
     * 序列化:序列化数据到文件中
     */
    public static void serialize(){
        Money money = javaObject();
        ByteArrayOutputStream bos = null;
        ObjectOutputStream oos = null;
        try {
            //序列化
            bos = new ByteArrayOutputStream();
            oos = new ObjectOutputStream(bos);
            oos.writeObject(money);

            FileOutputStream fos = new FileOutputStream(fileName);
            fos.write(bos.toByteArray());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bos.close();
                oos.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

    }

    /**
     * 反序列化:读取 序列化文件  实现反序列化
     */
    public static void deserialization(){
        ByteArrayInputStream bis = null;
        ObjectInputStream ois = null;
        try {
            FileInputStream fis = new FileInputStream(fileName);
            byte[] data = new byte[1024];
            fis.read(data);
            bis = new ByteArrayInputStream(data);
            ois = new ObjectInputStream(bis);
            Money copy = (Money)ois.readObject();
            System.out.println(copy.toString());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            try {
                bis.close();
                ois.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
    }
}

# 模拟一:在没有显示声明 serialVersionUID 下,执行 serialize() 生成 序列化文件。

# 测试1、直接执行 deserialization() 进行反序列化。结果成功
# 测试2、修改 Money.java 添加一个新的属性, deserialization() 进行反序列化,失败。

# 模拟2:显示声明 serialVersionUID 下,重复 模拟1操作

# 测试1、直接执行 deserialization() 进行反序列化。结果成功
# 测试2、、修改 Money.java 添加一个新的属性, deserialization() 进行反序列化,结果成功。

# 结论

# 1. 在java中,只要一个类实现了java.io.Serializable接口,那么它就可以被序列化

# 2. 通过ObjectOutputStream和ObjectInputStream对对象进行序列化合反序列化操作

# 3. 对象是否允许被反序列化,不仅仅是取决于对象的代码是否一致,同时还有一个重要的因素(UID)

# 4. 序列化不保存静态变量

# 5. 要想父类对象也参与序列化操作,那么必须要让父类也实现Serializable接口

# 6. Transient关键字,主要是控制变量是否能够被序列化。如果没有被序列化的成员变量反序列化后,会被设置成初始值,比如String -> null

# 7. 通过序列化操作实现深度克隆

精彩内容推送,请关注公众号!
最近更新时间: 3/24/2020, 9:44:42 PM