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 ,其他字段完整映射

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章