JAVA學(xué)習(xí)-序列化與反序列化

序列化與反序列化

簡(jiǎn)介

1.序列化是將對(duì)象狀態(tài)轉(zhuǎn)換可保存或傳輸格式的過(guò)程

2.反序列化是將流轉(zhuǎn)化為對(duì)象的過(guò)程

應(yīng)用場(chǎng)景

1.將對(duì)象序列化永久的保存在磁盤(pán)上,例如Tomcat中將session就是序列化到磁盤(pán)中,這樣做可以減少內(nèi)存消耗

2.用于網(wǎng)絡(luò)中傳輸?shù)淖止?jié)序列,例如RPC框架中將對(duì)象序列化之后傳輸

實(shí)例

實(shí)現(xiàn)序列化與反序列化的方式主要有兩種,第一種實(shí)現(xiàn)Serialable接口,第二種實(shí)現(xiàn)實(shí)現(xiàn)Externalizable接口,如下會(huì)詳細(xì)介紹這兩種方式。

1.實(shí)現(xiàn)Serialable接口

如下代碼是對(duì)Person類(lèi)進(jìn)行序列化的實(shí)例,如下為Person實(shí)體類(lèi)實(shí)現(xiàn)了Serializable接口

public class Person implements Serializable{

    private static final long serialVersionUID = 1L;

    private String name;
    
    private Integer age;
    
    private String sex;
    
    ...//此處省略的部分代碼
}

從上面代碼中可以看出,首先要實(shí)現(xiàn)類(lèi)的對(duì)象可以被序列化,首先的實(shí)現(xiàn)Serializable接口,還需要添加屬性serialVersionUID

1.1 屬性serialVersionUID的作用

在代碼中常用設(shè)置該屬性的值如下所示

//這是默認(rèn)方式
private static final long serialVersionUID = 1L;

//生成的
private static final long serialVersionUID = -2907193193159218377L;

在對(duì)象序列化時(shí)該屬性用于控制版本, 意思就是在序列化時(shí)該值就對(duì)應(yīng)著一個(gè)版本,反序列化時(shí)也會(huì)根據(jù)這個(gè)值進(jìn)行,若不顯示指定這個(gè)值,在類(lèi)編譯時(shí)期,java編譯器會(huì)自動(dòng)的給它加上一個(gè)UID,但是會(huì)出現(xiàn)的問(wèn)題是,只要對(duì)類(lèi)文件做了修改哪怕是新增了一個(gè)空格,都會(huì)導(dǎo)致UID變化,反序列化時(shí)就會(huì)出現(xiàn)問(wèn)題,因此在代碼中盡量明確指明這個(gè)值。

1.2 對(duì)象序列化

如下代碼通過(guò)ObjectOutputStream將對(duì)象Object序列化保存到文件中(fileName對(duì)應(yīng)的文件)

/** 序列化對(duì)象 **/
public static void serialObject(Object obj,String filename){
    FileOutputStream out = null;
    ObjectOutputStream objOut = null;
    try {
        out = new FileOutputStream(filename);
        objOut = new ObjectOutputStream(out);
        objOut.writeObject(obj);
    } catch (Exception e) {
        // TODO: handle exception
    } finally{
        try {
            if (null != out) {
                out.close();
            }
            if (null != objOut) {
                objOut.close();
            }
        } catch (Exception e2) {
            // TODO: handle exception
        }
    }
}
1.3 讀取文件中序列化的對(duì)象

如下代碼中是將文件中讀取數(shù)據(jù),然后反序列化

/**反序列化對(duì)象**/
public static Object unSerialObject(String filename){
    Object obj = null;
    File file = new File(filename);
    FileInputStream in = null;
    ObjectInputStream objIn = null;
    try {
        in = new FileInputStream(file);
        objIn = new ObjectInputStream(in);
        return objIn.readObject();
    } catch (Exception e) {
        e.printStackTrace();
    } finally{
        try {
            if (null != in) {
                in.close();
            }
            if (null != objIn) {
                objIn.close();
            }
        } catch (Exception e2) {
            e2.printStackTrace();
        }
    }
    return obj;
}
1.4 測(cè)試及結(jié)果

測(cè)試代碼如下:

public static void main(String[] args) {
    //構(gòu)造對(duì)象
    Person person  = new Person();
    person.setAge(11);
    person.setName("張三");
    person.setSex("男");
    
    String fileName = "D://a.txt";
    //序列化
    serialObject(person, fileName);
    
    //反序列化
    Person newPerson = (Person)unSerialObject(fileName);
    System.out.println(newPerson);
}

結(jié)果如下:

1.在對(duì)應(yīng)目錄生產(chǎn)了a.txt文件

2.如下圖所示

[ name:張三,age:11, sex:男]

2.實(shí)現(xiàn)Externalizable接口

如下代碼為實(shí)現(xiàn)Externalizable接口的進(jìn)行序列化操作的過(guò)程

public class NewPerson implements Externalizable{
    
    private static final long seriaVersionUID = 1L;
    
    private String name;
    
    private Integer age;
    
    private String sex;
    
    @Override
    public void writeExternal(ObjectOutput out) throws IOException {
        out.writeObject(name);
        out.writeObject(age);
        out.writeObject(sex);
    }

    @Override
    public void readExternal(ObjectInput in) throws IOException,
            ClassNotFoundException {
        //注意的是讀取的順序和寫(xiě)入的順序一樣
        name = (String) in.readObject();
        age = (Integer) in.readObject();
        sex = (String) in.readObject();
    }
    
    ...//此處省略部分代碼

}

從代碼中可以看出,實(shí)現(xiàn)Externalizable接口后需要實(shí)現(xiàn)兩個(gè)方法,而這兩個(gè)方法正是與方法一的區(qū)別之處,可以控制序列化的對(duì)象,當(dāng)然第一種方法中也可以部分字段序列化,使用 transient關(guān)鍵字,或者使用static去修飾屬性

3.序列化與反序列化需要注意的點(diǎn)

3.1 對(duì)于對(duì)象中包含其他對(duì)象的,所有對(duì)象實(shí)現(xiàn)序列化接口

如下實(shí)例,Person中引用了Teacher類(lèi)

public class Person implements Serializable{

    private static final long serialVersionUID = 1L;
    
    private String name;
    
    private Integer age;
    
    private String sex;

    private Teacher teacher;

    ...//此處省略了部分代碼
}

如下測(cè)試代碼,若person對(duì)象中未引用Teacher對(duì)象,對(duì)于序列化而言沒(méi)有任何引用,能夠正常輸出,但是若引用了Teacher對(duì)象,則會(huì)報(bào)異常,分析源碼可知,ObjectOutputStream進(jìn)行序列化得過(guò)程,實(shí)際上時(shí)循環(huán)處理的,這對(duì)于這種嵌套的對(duì)象,需要全部序列化。

public static void main(String[] args) {
    //構(gòu)造對(duì)象
    Person person  = new Person();
    person.setAge(11);
    person.setName("張三");
    person.setSex("男");
    //不加以下代碼不會(huì)報(bào)錯(cuò)
    //Teacher te = new Teacher();
    //te.setName("王五");
    //person.setTeacher(te);
}
3.2 若父類(lèi)實(shí)現(xiàn)了Serializable接口,子類(lèi)繼承父類(lèi)也可以被序列化,這個(gè)應(yīng)該很容易理解
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
【社區(qū)內(nèi)容提示】社區(qū)部分內(nèi)容疑似由AI輔助生成,瀏覽時(shí)請(qǐng)結(jié)合常識(shí)與多方信息審慎甄別。
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書(shū)系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

相關(guān)閱讀更多精彩內(nèi)容

  • JAVA序列化機(jī)制的深入研究 對(duì)象序列化的最主要的用處就是在傳遞,和保存對(duì)象(object)的時(shí)候,保證對(duì)象的完整...
    時(shí)待吾閱讀 11,224評(píng)論 0 24
  • 原帖地址:原帖個(gè)人網(wǎng)站地址:個(gè)人網(wǎng)站簡(jiǎn)書(shū)對(duì)markdown的支持太完美了,我竟然可以直接Ctrl C/V過(guò)來(lái)。 定...
    ryderchan閱讀 3,951評(píng)論 1 9
  • 一、 序列化和反序列化概念 Serialization(序列化)是一種將對(duì)象以一連串的字節(jié)描述的過(guò)程;反序列化de...
    步積閱讀 1,495評(píng)論 0 10
  • 官方文檔理解 要使類(lèi)的成員變量可以序列化和反序列化,必須實(shí)現(xiàn)Serializable接口。任何可序列化類(lèi)的子類(lèi)都是...
    獅_子歌歌閱讀 2,561評(píng)論 1 3
  • 首先請(qǐng)列出一個(gè)清單寫(xiě)下自己想要實(shí)現(xiàn)的事情 想,請(qǐng)大膽一點(diǎn)! 接下來(lái),去完成它們
    RWBY閱讀 230評(píng)論 0 1

友情鏈接更多精彩內(nèi)容