序列化和反序列化

Serializable

簡述

序列化就是將某個(gè)對(duì)象轉(zhuǎn)換成特定的數(shù)據(jù)格式,反序列化即序列化的返操作。一般將序列化后的數(shù)據(jù)通過網(wǎng)絡(luò)傳輸或者保存到數(shù)據(jù)庫。

java的序列化操作

在Java中,若要將一個(gè)對(duì)象可序列化則要實(shí)現(xiàn) Serializable接口。且盡可能標(biāo)記屬性serialVersionUID(后面Test將說明為什么要標(biāo)記此屬性),一般IDEA會(huì)自動(dòng)生成。

  • 如我有一列
class Order implements Serializable {
    
    private static final long serialVersionUID = 1L;
    
    private String orderNo;
    private int amount;
    
    //構(gòu)造
    //getter setter...
    
    @Override
    public String toString() {
       //所有屬性
    }
}

現(xiàn)在將利用java.io包下的ObjectOutputStreamFileOutputStream 來演示如何將Order對(duì)象序列化到文件里保存起來

public class SerializableTest {

    public final static String PATH = "/tmp/order.txt";

    @Test
    public void test_serializable() throws IOException {
        Order o = new Order("abc", 1299, new Address("安徽"), new Person("Savey"));
        try ( FileOutputStream fstream =  new FileOutputStream(PATH);
              ObjectOutputStream objectOutputStream = new ObjectOutputStream(fstream)
        ) {
            
            //接收一個(gè)對(duì)象、并將對(duì)象轉(zhuǎn)為字節(jié)流
            objectOutputStream.writeObject(o);
            //刷新到輸出fstream
            objectOutputStream.flush();
        }
    }
}

此時(shí) Order對(duì)象已經(jīng)被序列化到 /tmp/order.txt文件里。

java的反序列化操作

如上回說到Order已經(jīng)被我們保存到指定文件,此時(shí)我們想讀取數(shù)據(jù)則這樣處理

    @Test
    public void test_covert_object() throws IOException, ClassNotFoundException {
        try (FileInputStream fileInputStream = new FileInputStream(PATH);
             ObjectInputStream objectInputStream = new ObjectInputStream(fileInputStream)
        ) {
            
            //從一個(gè)輸入流讀取數(shù)據(jù)轉(zhuǎn)為對(duì)象,這里加個(gè)強(qiáng)轉(zhuǎn)為Order
            Order o = (Order)objectInputStream.readObject();

            System.out.println(o);
        }
    }

此時(shí)我們利用了幾個(gè)重要的對(duì)象幫助我們序列和反序列操作

import java.io.FileOutputStream;
import java.io.ObjectOutputStream;
import java.io.FileInputStream;
import java.io.ObjectInputStream;
import java.io.Serializable;

注意事項(xiàng)

serialVersionUID

假如我在序列化之前的 Order對(duì)象是這樣的

class Order implements Serializable {

    private static final long serialVersionUID = 1L;
    
}

在反序列化之后serialVersionUID變了

class Order implements Serializable {

    private static final long serialVersionUID = 2L;
    
}

那么不好意思,會(huì)報(bào)錯(cuò),如下:

java.io.InvalidClassException: Order; local class incompatible: stream classdesc serialVersionUID = 1, local class serialVersionUID = 2

序列化對(duì)象里有其他自定義對(duì)象

比如我在Order里加了一個(gè)Person對(duì)象

class Order implements Serializable {
    private static final long serialVersionUID = 1L;
    
    //其他屬性
    
     private Person person;
    
    //getter setter construct toString
    
}


class Person implements Serializable {

    private static final long serialVersionUID = 2L;
}

如果Person沒有實(shí)現(xiàn)Serializable接口也會(huì)出錯(cuò),如下:

java.io.NotSerializableException: Person

But 你可以修改Person的申明方式

private transient Person person;

用關(guān)鍵字transient來修飾您不想序列化的屬性!在ArrayList源碼里 是不是也見過這個(gè)關(guān)鍵字呢???

/**
     * The array buffer into which the elements of the ArrayList are stored.
     * The capacity of the ArrayList is the length of this array buffer. Any
     * empty ArrayList with elementData == DEFAULTCAPACITY_EMPTY_ELEMENTDATA
     * will be expanded to DEFAULT_CAPACITY when the first element is added.
     */
    transient Object[] elementData; // non-private to simplify nested class access

自定義序列化

不錯(cuò),您還可以自定義你要序列化的內(nèi)容,java很優(yōu)雅的為我們提供了兩個(gè)方法重寫序列化的方法

private void writeObject(ObjectOutputStream oos)

private void readObject(ObjectInputStream ois)

這兩個(gè)方法見名思意,一個(gè)寫入、一個(gè)讀取。如上回說到一個(gè)屬性被關(guān)鍵寫transient修飾了,但我還想將它序列化下~

class Order implements Serializable {
    
    //其他屬性
    private transient Person person;
    

    private void writeObject(ObjectOutputStream oos)
            throws IOException {
        oos.defaultWriteObject();
        
        //自定義寫入Person這個(gè)對(duì)象、盡管你是 transient修飾了?。?        oos.writeObject(person);
    }
        
        

    private void readObject(ObjectInputStream ois)
            throws ClassNotFoundException, IOException {
        ois.defaultReadObject();
        
        //讀取強(qiáng)行轉(zhuǎn)成Person對(duì)象
        Person person = (Person) ois.readObject();
        this.setPerson(person);
    }        


    //getter setter construct
    
}

上面代碼演示了如果自定義序列化和反序列化,如果你有多個(gè)屬性要自定義操作,請(qǐng)注意的寫入的順序,和讀取的順序要一一對(duì)應(yīng),不然會(huì)出錯(cuò)的哦!

java.lang.ClassCastException: XXX cannot be cast to XXX
最后編輯于
?著作權(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),簡書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。

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

  • JAVA序列化機(jī)制的深入研究 對(duì)象序列化的最主要的用處就是在傳遞,和保存對(duì)象(object)的時(shí)候,保證對(duì)象的完整...
    時(shí)待吾閱讀 11,192評(píng)論 0 24
  • 序列化是一種對(duì)象持久化的手段。普遍用在網(wǎng)絡(luò)傳輸,RMI(遠(yuǎn)程方法調(diào)用),對(duì)象保存到本地等。 序列化的含義,意義和使...
    程序員的交流電閱讀 499評(píng)論 0 1
  • What? 何為序列化與反序列化?序列化:將對(duì)象轉(zhuǎn)化為二進(jìn)制序列的過程反序列化:將二進(jìn)制序列恢復(fù)為原始對(duì)象的過程 ...
    LilacZiyun閱讀 3,131評(píng)論 0 15
  • 1.序列化的意義2.java原生序列化3.serialVersionUID 的作用4.靜態(tài)變量序列化5.父類的序列...
    Carol_6a27閱讀 464評(píng)論 0 0
  • 對(duì)象序列化的目標(biāo): 將對(duì)的字節(jié)序列對(duì)象永久的保存到磁盤中。 允許在網(wǎng)絡(luò)上直接傳輸對(duì)象,傳輸對(duì)象的字節(jié)序列。 對(duì)象序...
    年少懵懂丶流年夢(mèng)閱讀 1,214評(píng)論 0 3

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