你不得不知道的對象的序列化和反序列化

對象的序列化和反序列化

序列化 (Serialization)將對象的狀態(tài)信息轉換為可以存儲或傳輸?shù)男问降倪^程浮入。在序列化期間塑悼,對象將其當前狀態(tài)寫入到臨時或持久性存儲區(qū)讥蔽。以后疏咐,可以通過從存儲區(qū)中讀取或反序列化對象的狀態(tài)供炼,重新創(chuàng)建該對象兼蕊。

當你創(chuàng)建對象時集侯,只要你需要养筒,它就會一直存在砌函,但是當程序終止的時候斩披,那么這個對象也就隨之消失了,盡管這么做是有意義的,但是仍舊存在某些的情況雏掠,如果對象能夠在程序不運行的情況下仍能存在并且保存其信息斩祭,那將會是非常有用的。這樣在下次運行程序的同事乡话,該對象能夠被重建并且擁有的信息與程序上次運行時它所擁有的信息相同摧玫。

簡單來說序列化和反序列化如下

  • 序列化:把對象轉換為字節(jié)序列的過程稱為對象的序列化
  • 反序列化:把字節(jié)序列恢復為對象的過程稱為對象的反序列化

而什么時候會用到序列化呢?一般在以下的情況中會使用到序列化

  • 對象的持久化:把對象的字節(jié)序列永久地保存到硬盤上绑青,通常存放在一個文件中

在很多應用中诬像,需要對某些對象進行序列化,讓它們離開內存空間闸婴,入住物理硬盤坏挠,以便長期保存。比如最常見的是Web服務器中的Session對象邪乍,當有 10萬用戶并發(fā)訪問降狠,就有可能出現(xiàn)10萬個Session對象,內存可能吃不消庇楞,于是Web容器就會把一些seesion先序列化到硬盤中榜配,等要用了,再把保存在硬盤中的對象還原到內存中吕晌。

  • 遠程調用:在網(wǎng)絡上傳送對象的字節(jié)序列

當兩個進程在進行遠程通信時蛋褥,彼此可以發(fā)送各種類型的數(shù)據(jù)。無論是何種類型的數(shù)據(jù)睛驳,都會以二進制序列的形式在網(wǎng)絡上傳送烙心。發(fā)送方需要把這個Java對象轉換為字節(jié)序列,才能在網(wǎng)絡上傳送乏沸;接收方則需要把字節(jié)序列再恢復為Java對象淫茵。

序列化的基本實現(xiàn)

只要對象實現(xiàn)了Serializable接口,對象的序列化就會變得十分簡單屎蜓。要序列化一個對象首先要創(chuàng)建某些OutputStream對象痘昌,然后將其封裝在一個ObejctOutputStream對象內,這時只需要調用writeObject()即可將對象序列化炬转,并將其發(fā)送給OutputStream辆苔。

對象序列化是基于字節(jié)的,所以要使用InputStreamOutputStream繼承層次結構

如果要反向上面的過程(即將一個序列還原為一個對象)扼劈,需要將一個InputStream封裝在ObjectInputStream內驻啤,然后調用readObject(),和往常一樣荐吵,我們最后獲得是一個引用骑冗,它指向了一個向上轉型的Object赊瞬,所以必須向下轉型才能直接設置它們。

對象序列化不僅能夠將實現(xiàn)了接口的那個類進行序列化贼涩,也能夠將其引用的對象也實例化巧涧,以此類推。這種情況可以被稱之為對象網(wǎng)遥倦。單個對象可與之建立連接谤绳。

下面我們舉個例子可以看到在序列化和反序列過程中,對象網(wǎng)中的連接的對象信息都沒有變袒哥。

public class TestSerializable {
    public static void main(String[] args) throws IOException, ClassNotFoundException {
        String fileName = "/Users/hupengfei/mytest.sql";
        Worm w = new Worm(6,'a');
        System.out.println("w:"+w);
        ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(fileName));
        out.writeObject("Worm Storage\n");
        out.writeObject(w);
        out.close();
        ObjectInputStream in = new ObjectInputStream(new FileInputStream(fileName));
        String s = (String) in.readObject();
        Worm w2 = (Worm) in.readObject();
        System.out.println(s+"w2:"+w2);
    }
}

class Data implements Serializable{
    private Integer i ;
    public Data(Integer i ){
        this.i = i;
    }

    @Override
    public String toString() {
        return i.toString();
    }
}

class Worm implements Serializable{

    private static final long serialVersionUID = 8033549288339500180L;

    private static Random random = new Random(47);

    private Data [] d = {
            new Data(random.nextInt(10)),
            new Data(random.nextInt(10)),
            new Data(random.nextInt(10))
    };

    private Worm next;
    private char c;
    public Worm(int i ,char x){
        System.out.println("Worm Constructor:"+i);
        c = x;
        if (--i>0){
            next = new Worm(i,(char)(x+1));
        }
    }

    public Worm(){
        System.out.println("Default Constructor");
    }

    @Override
    public String toString() {
        StringBuffer result = new StringBuffer(":");
        result.append(c);
        result.append("(");
        for (Data data: d){
            result.append(data);
        }
        result.append(")");
        if (next!=null){
            result.append(next);
        }
        return result.toString();
    }
}

可以看到打印信息如下

Worm Constructor:6
Worm Constructor:5
Worm Constructor:4
Worm Constructor:3
Worm Constructor:2
Worm Constructor:1
w::a(853):b(119):c(802):d(788):e(199):f(881)
Worm Storage
w2::a(853):b(119):c(802):d(788):e(199):f(881)

在生成Data對象時是用隨機數(shù)初始化的缩筛,從輸出中可以看出,被還原后的對象確實包含了原對象中的所有鏈接堡称。

上面我們舉了個如何進行序列化的例子瞎抛,其中或許看到了serialVersionUID這個字段,如果不加的話却紧,那么系統(tǒng)會自動的生成一個桐臊,而如果修改了類的話,哪怕加一個空格那么這個serialVersionUID也會改變啄寡,那么在反序列化的時候就會報錯豪硅,因為在反序列化的時候會將serialVersionUID和之前的serialVersionUID進行對比,只有相同的時候才會反序列化成功挺物。所以還是建議顯視的定義一個serialVersionUID

transient(瞬時)關鍵字

當我們在對序列化進行控制的時候飘弧,可能需要某個字段不想讓Java進行序列化機制進行保存其信息與恢復识藤。如果一個對象的字段保存了我們不希望將其序列化的敏感信息(例如密碼)。盡管我們使用private關鍵字但是如果經過序列化次伶,那么在進行反序列化的時候也是能將信息給恢復過來的痴昧。我們舉個例子如下:

我們定義個Student

class Student implements Serializable{
    private static final long serialVersionUID = 1734284264262085307L;
    private String password;
------get set 方法
}

然后將其序列化到文件中然后再從文件中反序列化

public static void main(String[] args) throws IOException, ClassNotFoundException {
    String fileName="/Users/hupengfei/mytest.sql";
    Student student = new Student();
    student.setPassword("123456");
    ObjectOutputStream objectOutputStream = new ObjectOutputStream(new FileOutputStream(fileName));
    objectOutputStream.writeObject(student);
    ObjectInputStream objectInputStream = new ObjectInputStream(new FileInputStream(fileName));
    Student readStudent = (Student) objectInputStream.readObject();
    System.out.println(readStudent.getPassword());
}

然后發(fā)現(xiàn)輸出為

readStudent的password=123456

此時我們如果想password參數(shù)在序列化的時候存儲其值,那么可以加上transient關鍵字冠王,就像下面一樣

private transient String password;

然后輸出如下

readStudent的password=null

發(fā)現(xiàn)在序列化的時候參數(shù)就已經沒被保存進去了

參考文章

?著作權歸作者所有,轉載或內容合作請聯(lián)系作者
  • 序言:七十年代末赶撰,一起剝皮案震驚了整個濱河市,隨后出現(xiàn)的幾起案子柱彻,更是在濱河造成了極大的恐慌豪娜,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,744評論 6 502
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件哟楷,死亡現(xiàn)場離奇詭異瘤载,居然都是意外死亡,警方通過查閱死者的電腦和手機卖擅,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,505評論 3 392
  • 文/潘曉璐 我一進店門鸣奔,熙熙樓的掌柜王于貴愁眉苦臉地迎上來墨技,“玉大人,你說我怎么就攤上這事挎狸】弁簦” “怎么了?”我有些...
    開封第一講書人閱讀 163,105評論 0 353
  • 文/不壞的土叔 我叫張陵锨匆,是天一觀的道長私痹。 經常有香客問我,道長统刮,這世上最難降的妖魔是什么紊遵? 我笑而不...
    開封第一講書人閱讀 58,242評論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮侥蒙,結果婚禮上暗膜,老公的妹妹穿的比我還像新娘。我一直安慰自己鞭衩,他們只是感情好学搜,可當我...
    茶點故事閱讀 67,269評論 6 389
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著论衍,像睡著了一般瑞佩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上坯台,一...
    開封第一講書人閱讀 51,215評論 1 299
  • 那天炬丸,我揣著相機與錄音,去河邊找鬼蜒蕾。 笑死稠炬,一個胖子當著我的面吹牛,可吹牛的內容都是我干的咪啡。 我是一名探鬼主播首启,決...
    沈念sama閱讀 40,096評論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼撤摸!你這毒婦竟也來了毅桃?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 38,939評論 0 274
  • 序言:老撾萬榮一對情侶失蹤准夷,失蹤者是張志新(化名)和其女友劉穎钥飞,沒想到半個月后,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體冕象,經...
    沈念sama閱讀 45,354評論 1 311
  • 正文 獨居荒郊野嶺守林人離奇死亡代承,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 37,573評論 2 333
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發(fā)現(xiàn)自己被綠了渐扮。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片论悴。...
    茶點故事閱讀 39,745評論 1 348
  • 序言:一個原本活蹦亂跳的男人離奇死亡掖棉,死狀恐怖,靈堂內的尸體忽然破棺而出膀估,到底是詐尸還是另有隱情幔亥,我是刑警寧澤,帶...
    沈念sama閱讀 35,448評論 5 344
  • 正文 年R本政府宣布察纯,位于F島的核電站帕棉,受9級特大地震影響,放射性物質發(fā)生泄漏饼记。R本人自食惡果不足惜香伴,卻給世界環(huán)境...
    茶點故事閱讀 41,048評論 3 327
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望具则。 院中可真熱鬧即纲,春花似錦、人聲如沸博肋。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,683評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽匪凡。三九已至膊畴,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間病游,已是汗流浹背唇跨。 一陣腳步聲響...
    開封第一講書人閱讀 32,838評論 1 269
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留礁遵,地道東北人轻绞。 一個月前我還...
    沈念sama閱讀 47,776評論 2 369
  • 正文 我出身青樓,卻偏偏與公主長得像佣耐,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子唧龄,可洞房花燭夜當晚...
    茶點故事閱讀 44,652評論 2 354

推薦閱讀更多精彩內容