serialVersionUID 实际的作用

serialVersionUID 实际作用

JAVA 中对序列化的支持 都是需要实现 Serializable 接口,然后需要声明一个serialVersionUID (也可以不用申明).
serialVersionUID 的作用是什么呢?
JAVA序列化的机制是通过判断类的serialVersionUID来验证的版本一致的。在进行反序列化时,JVM会把传来的字节流中的serialVersionUID于本地相应实体类的serialVersionUID进行比较。如果相同说明是一致的,可以进行反序列化

serialVersionUID 申明方式

  • 显示声明
public class User implements Serializable {

    private static final long serialVersionUID = -3350966179389669783L;
    private String name;

显示申明是根据类名 字段 参数 生成的一个64位的hash值(申明之后就不会变了 就算修改了类信息)

  • 隐式申明
public class User implements Serializable {
   private String name;

隐式申明 也是会根据类名 字段 参数 生成的一个64位的hash值(但是每次类信息修改 都会重新生成)

类字段新增与sid声明方式

  • 新增字段&sid 隐式申明

声明 User 类 (不申明serialVersionUID)持久化到文件, 在User 类中新增字段 在从文件读取

申明User类

public class User implements Serializable {

    private String name;

    private int age;

写入序列化文件

    private static final String FILE = "/Users/xxx/Desktop/dto";

    @Test
    public void serialize() {
        User user = new User();
        user.setName("sunla");
        user.setAge(31);

        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream os = new ObjectOutputStream(bos);

            os.writeObject(user);
            os.close();
            bos.close();
            FileUtils.writeByteArrayToFile(new File(FILE),bos.toByteArray());
        } catch (IOException e) {
            throw new IllegalArgumentException("Non-serializable object", e);
        }
    }

user类新增字段

public class User implements Serializable {

    private String name;

    private int age;
    /** 新增属性 */
    private HashSet<String> sets = new HashSet<>();

执行从文件反序列化操作

	private static final String FILE = "/Users/xxx/Desktop/dto";
    @Test
    public void deserialize() {
        Object rv = null;
        try {
            byte[] in = FileUtils.readFileToByteArray(new File(FILE));
            if (in != null) {
                ByteArrayInputStream bis = new ByteArrayInputStream(in);
                ObjectInputStream is = new ObjectInputStream(bis);

                rv = is.readObject();
                is.close();
                bis.close();
            }
            User user = (User)rv;
            System.out.println(JSON.toJSONString(user));
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

执行的结果

java.io.InvalidClassException: com.test.serial.User; local class incompatible: stream classdesc serialVersionUID = 7212634958119174257, local class serialVersionUID = 5030622290002077224

	at java.io.ObjectStreamClass.initNonProxy(ObjectStreamClass.java:687)
	at java.io.ObjectInputStream.readNonProxyDesc(ObjectInputStream.java:1880)
	at java.io.ObjectInputStream.readClassDesc(ObjectInputStream.java:1746)
	at java.io.ObjectInputStream.readOrdinaryObject(ObjectInputStream.java:2037)
	at java.io.ObjectInputStream.readObject0(ObjectInputStream.java:1568)
	at java.io.ObjectInputStream.readObject(ObjectInputStream.java:428)

执行结果报错了,2个很明显的 serialVersionUID 不一样 导致反序列化失败,就是前面说到的 隐式声明的sid 当新增字段后会变更

  • 新增字段 & sid 显示申明

声明 User 类 (申明serialVersionUID)持久化到文件, 在User 类中新增字段 在从文件读取

申明User类

public class User implements Serializable {

    private static final long serialVersionUID = -3350966179389669783L;

    private String name;

    private int age;

写入序列化文件

    private static final String FILE = "/Users/xxx/Desktop/dto";

    @Test
    public void serialize() {
        User user = new User();
        user.setName("sunla");
        user.setAge(31);

        try {
            ByteArrayOutputStream bos = new ByteArrayOutputStream();
            ObjectOutputStream os = new ObjectOutputStream(bos);

            os.writeObject(user);
            os.close();
            bos.close();
            FileUtils.writeByteArrayToFile(new File(FILE),bos.toByteArray());
        } catch (IOException e) {
            throw new IllegalArgumentException("Non-serializable object", e);
        }
    }

user类新增字段

public class User implements Serializable {

    private static final long serialVersionUID = -3350966179389669783L;

    private String name;

    private int age;
    /** 新增属性(这里使用了集合 反序列化出来大家可以猜下 调用getSets的结果) */
    private HashSet<String> sets = new HashSet<>();

执行从文件反序列化操作

	private static final String FILE = "/Users/xxx/Desktop/dto";
    @Test
    public void deserialize() {
        Object rv = null;
        try {
            byte[] in = FileUtils.readFileToByteArray(new File(FILE));
            if (in != null) {
                ByteArrayInputStream bis = new ByteArrayInputStream(in);
                ObjectInputStream is = new ObjectInputStream(bis);

                rv = is.readObject();
                is.close();
                bis.close();
            }
            User user = (User)rv;
            System.out.println(JSON.toJSONString(user));
            System.out.println(user.getSets() == null ? "set null":"set not null");
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

执行的结果

{"age":31,"name":"sunla"}
set null

执行结果 是新增的集合对象是个null ,其他字段完整映射

你可能感兴趣的:(java)