序列化ID是什麼?

赫於富發表於2020-11-21

一、前言:

現在的實體類不單單要實現 Serializable,還要生成一個序列化ID,如下:

那麼這個序列化ID是怎麼生成的呢?

File -> Settings -> Editor -> Inspections -> 搜尋 Serialization issues ,找到 Serializable class without 'serialVersionUID' ->打上勾,Apply->OK

 

 

最後可以看到已經生成了序列化ID:

 

這個時候很多人就會產生疑問,我們的實體已經實現了Serializable那為什麼需要新增這個序列化ID?

二、序列化ID有什麼作用?

      這個序列化ID起著關鍵的作用,它決定這是否能夠成功反序列化,簡單的來說就是,java的序列化機制是通過執行時判斷類的serialVersionUID來驗證版本是否一致,在進行反序列化的時候,JVM會傳來位元組流中的serialVersionUID與本地實體類中的serialVersionUID進行對比,如果相同則認為一致可以進行反序列化,否則就會報異常

那麼這個時候肯定會有人問: 我實現了Serializable之後同樣也可以進行序列化和反序列化啊,也沒有寫這個序列UID也沒有報錯啊?

       告訴你: 如果實體裡面沒有顯示的定義一個serialVersionUID ,Java序列化機制會根據編譯的class自動生成一個serialVersionUID,比如,當我們編寫一個實體類的時候,後來發現業務需要新增新的欄位,這個時候如果再次反序列化的時候就會出現sersionVersionUID不一致,導致反序列化失敗,那麼如何解決這個問題?

便是在本地類的實體中顯示定義一個serialVersionUID變數 這個時候每次編譯的時候值都保持不變

三、下面我們用程式碼來驗證一下如果沒有serialVersionUID的時候,由於值不同報錯:

1.先定義一個實體類:

package com.example.entity;/*
 * Copyright 2013-2020 Smartdot Technologies Co., Ltd. All rights reserved.
 * SMARTDOT PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 */

import java.io.Serializable;

/**
 * <p>
 *
 * @author <a href="mailto:heyf@smartdot.com.cn">heyf</a>
 * @version 1.0, 2020-11-21 09:43:22
 * @class
 * @date 2020-11-21 09:43:22
 * @see </p>
 */
public class SerialEntity implements Serializable {
    
    private String age;
    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }


}

2.執行序列化程式碼:

package com.example.controller;/*
 * Copyright 2013-2020 Smartdot Technologies Co., Ltd. All rights reserved.
 * SMARTDOT PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 */


import com.example.entity.SerialEntity;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileNotFoundException;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.ObjectOutputStream;

/**
 * 序列化
 * <p>
 *
 * @class ObjSerializeAndDeserializeTest
 * @date 2020-11-21 09:39:29
 * @author <a href="mailto:heyf@smartdot.com.cn">heyf</a>
 * @version 1.0, 2020-11-21 09:39:29
 * @see </p>
 */

public class ObjSerializeAndDeserializeTest {
    public static void main(String[] args) {
        SerializePerson();
    }

    /*
     * @Author HYF
     * @Description //TODO驗證序列化id存在的意義
     * @Date 9:41 2020/11/21
     * @Param []
     * @return void
     **/
    public static void SerializePerson(){
        Logger logger = LoggerFactory.getLogger(ObjSerializeAndDeserializeTest.class);
        SerialEntity serialEntity=new SerialEntity();
        serialEntity.setAge("30");
        //建立一個輸出流
        ObjectOutputStream outputStream=null;
        try{
            outputStream=new ObjectOutputStream(new FileOutputStream("D:\\1.實習\\-quartz-demo\\static\\test.txt"));
            //
            outputStream.writeObject(serialEntity);
            logger.info(serialEntity.toString());
            logger.info("序列化成功");
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        } finally {
            try{
                //關閉輸出流
                outputStream.close();
            }catch(IOException e){
                e.printStackTrace();
            }

        }
    }
}

結果:

這個時候我們發現業務有些變動我們需要在實體中新增新的欄位:

在上面實體類的基礎上新增了一個name欄位:

package com.example.entity;/*
 * Copyright 2013-2020 Smartdot Technologies Co., Ltd. All rights reserved.
 * SMARTDOT PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 */

import java.io.Serializable;

/**
 * <p>
 *
 * @author <a href="mailto:heyf@smartdot.com.cn">heyf</a>
 * @version 1.0, 2020-11-21 09:43:22
 * @class
 * @date 2020-11-21 09:43:22
 * @see </p>
 */
public class SerialEntity implements Serializable {

    private String age;
    private String name;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAge() {
        return age;
    }

    public void setAge(String age) {
        this.age = age;
    }


}

3.我們進行反序列化:

package com.example.controller;/*
 * Copyright 2013-2020 Smartdot Technologies Co., Ltd. All rights reserved.
 * SMARTDOT PROPRIETARY/CONFIDENTIAL. Use is subject to license terms.
 *
 */

import com.example.entity.SerialEntity;
import org.apache.ibatis.javassist.util.proxy.ProxyObjectInputStream;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import java.io.FileInputStream;
import java.io.FileNotFoundException;
import java.io.IOException;
import java.io.ObjectInputStream;


/**
 * 反序列化
 * <p>
 *
 * @author <a href="mailto:heyf@smartdot.com.cn">heyf</a>
 * @version 1.0,
 * @class
 * @date
 * @see </p>
 */
public class ObjSerializeAndDeserializeTest2 {
    public static void main(String[] args) {
        Logger logger= LoggerFactory.getLogger(ObjSerializeAndDeserializeTest2.class);
        SerialEntity serialEntity=DeserializePersion();
        logger.info(serialEntity.getAge());
        logger.info(serialEntity.getName());


    }

    private static SerialEntity DeserializePersion(){
        SerialEntity person = null;
        ObjectInputStream inputStream = null;
        try {
            inputStream = new ObjectInputStream(new FileInputStream("D:\\1.實習\\-quartz-demo\\static\\test.txt"));
            try {
                person = (SerialEntity) inputStream.readObject();
                System.out.println("執行反序列化過程成功。");
            } catch (ClassNotFoundException e) {
                e.printStackTrace();
            }
        } catch (FileNotFoundException e) {
            e.printStackTrace();
        } catch (IOException e) {
            e.printStackTrace();
        }  finally {
            try {
                inputStream.close();
            } catch (IOException e) {
                e.printStackTrace();
            }
        }
        return person;


}
}

結果發現報錯:

 報錯原因:就是說的SerialVersionUID不同所以失敗了

現在我們給實體類上加上serialVersionUID

然後重複上面的步驟,你就會發現都不會報錯了,因為每次的serialVersionUID的值都是我們顯示定義的,所以以後大家在寫實體的時候需要要實現序列化,建議最好加上序列化ID。

 

 

相關文章