关于java序列化问题

1.场景描述:最近在看序列化,遇到一些疑惑

  //父类

public class parent implements Serializable{

private static final long serialVersionUID = 7604030015683112269L; //UID

private String name;

//setter/getter...

}

//子类

public class Child extends parent {

//private String attr1;//序列化时注释此行代码,反序列化时取消注解

}

//测试类

public class Test{

public static void main(String[] args) throws Exception{

//serializeTest(); //先序列化,添加子类新属性后,注释并反序列化

Child c = deserializeTest();

System.out.println(c.toString());

}

/*序列化*/

public static void serializeTest() throws IOException {

Child c= new Child();

c.setName("wyy");

ObjectOutputStream oos = null;

try {

oos = new ObjectOutputStream(new FileOutputStream(new File("d:/test.txt")));

oos.writeObject(c);

System.out.println(c.toString());

System.out.println("序列化success");

} catch (IOException e) {

e.printStackTrace();

}finally {

oos.close();

}

}

/*反序列化*/

public static Rich deserializeTest() throws IOException {

Child c = null;

ObjectInputStream ois = null;

try {

ois = new ObjectInputStream(new FileInputStream(new File("d:/test.txt")));

c = (Child) ois.readObject();

System.out.println("反序列化成功");

} catch (IOException e) {

e.printStackTrace();

} catch (ClassNotFoundException e) {

e.printStackTrace();

}finally {

ois.close();

}

return c;

}

}

2.问题描述:

a.父类实现序列化接口

b.子类继承父类

c.先序列化子类对象,子类对象添加新属性后,再反序列化。抛出 InvalidClassException异常,UID不一致..

d.子类添加序列化ID后,反序列化正常执行

(个人理解是序列号类似“暗号”,序列化后,即使类新增了属性“改头换面”,只要“暗号”对上,

就可以正常识别旧的对象数据,反序列化就可以正常执行)

3.疑惑点:

    在日常开发中,没有太在意序列化ID。父类实现序列化接口,当子类新增属性后,也没有遇到过上述异常啊。

猜想是因为对象新增属性,对应的数据库也会新增相应字段,所以反序列化时仍能对应上?

但是平时也有用@Transient注解一些暂存字段,数据库没有对应列,也没遇到过InvalidClassException异常(猜想错误...)。

为啥测试用例中,如果没有serialVersionUID,子类添加新属性后再反序列化,会报错,而开发中常增加类的属性,且类中没有serialVersionUID,却没有报错?是因为连接了数据库吗??

==========================================================================
望对此了解的大佬,指点迷津...谢谢

回答:

不知道楼主有没有试过memcache等缓存来做测试。你的测试方法用的是java的对象序列化,当然对class字节码有严格的判断,在实际开发中,如果场景的是数据库中取出这个实体类,或者保存到数据库,这个过程并不涉及到java的对象序列化,所以可以任意添加字段。但是如果涉及到缓存存储,比如某些memcache的库存储对象就是用java的对象序列化来保存,这个时候就会有序列化、反序列化版本不一致的问题了。所以这个问题还是要看使用场景有没有设计到java的对象序列化。

回答:

测试如下
图片描述

序列化一个对象 B继承A A实现序列化接口 但不增加版本id 成功写入文件

接下来读取
图片描述

同样成功读取。
此时 给B 增加一个属性

clipboard.png

报错 版本id 不一致

此时我们 调用 w 方法 覆盖写入

clipboard.png

再调用r 方法成功读取
clipboard.png

测试代码

package com.iking.t;

import java.io.*;

class A implements Serializable {

//private static final long serialVersionUID = 383079475457546876L;

}

class B extends A {

private String ex;

}

public class Run {

public static void main(String[] args) throws Exception {

r();

}

private static void w() throws Exception {

File f = new File("d:\\serializable");

if (!f.exists()) f.createNewFile();

OutputStream out = new FileOutputStream(f);

ObjectOutputStream ojn = new ObjectOutputStream(out);

ojn.writeObject(new B());

ojn.close();

System.out.println("成功写入");

}

private static void r() throws Exception {

File f = new File("d:\\serializable");

InputStream in = new FileInputStream(f);

ObjectInputStream ojn = new ObjectInputStream(in);

Object o = ojn.readObject();

ojn.close();

B b = (B) o;

System.out.println("成功读取");

}

}

在项目中 entity 类总会去继承一些类 在这些类中都处理过 版本id的问题 所以子类不需要进行任何处理

结论

serialVersionUID  即使版本id 根据一个类的成员根据一定算法计算得出  若未指定 serialVersionUID  则在序列化时候 默认生成一个serialVersionUID 当你在序列化文件生成之后  给类增删成员 则改类的 serialVersionUID 值会发生变化  反序列化的时候  会比较 serialVersionUID   若序列化文件与类的serialVersionUID  不一致 则抛出此异常

clipboard.png

源码中也是直接这么比较的 不一致则抛出InvalidClassException 异常

以上是 关于java序列化问题 的全部内容, 来源链接: utcz.com/p/178588.html

回到顶部