Java序列化和反序列化(詳解)

一盟广、理解Java序列化和反序列化

Serialization(序列化):將java對象以一連串的字節(jié)保存在磁盤文件中的過程掸宛,也可以說是保存java對象狀態(tài)的過程泪幌。序列化可以將數(shù)據(jù)永久保存在磁盤上(通常保存在文件中)惊豺。

deserialization(反序列化):將保存在磁盤文件中的java字節(jié)碼重新轉(zhuǎn)換成java對象稱為反序列化呀非。

二坚俗、序列化和反序列化的應(yīng)用

兩個進(jìn)程在遠(yuǎn)程通信時镜盯,可以發(fā)送多種數(shù)據(jù),包括文本猖败、圖片速缆、音頻、視頻等恩闻,這些數(shù)據(jù)都是以二進(jìn)制序列的形式在網(wǎng)絡(luò)上傳輸艺糜。

java是面向?qū)ο蟮拈_發(fā)方式,一切都是java對象幢尚,想要在網(wǎng)絡(luò)中傳輸java對象破停,可以使用序列化和反序列化去實現(xiàn),發(fā)送發(fā)需要將java對象轉(zhuǎn)換為字節(jié)序列尉剩,然后在網(wǎng)絡(luò)上傳送真慢,接收方收到字符序列后,會通過反序列化將字節(jié)序列恢復(fù)成java對象理茎。

java序列化的優(yōu)點(diǎn):
實現(xiàn)了數(shù)據(jù)的持久化黑界,通過序列化可以把數(shù)據(jù)持久地保存在硬盤上(磁盤文件)。
利用序列化實現(xiàn)遠(yuǎn)程通信皂林,在網(wǎng)絡(luò)上傳輸字節(jié)序列园爷。

三、序列化和反序列化地實現(xiàn)

1.JDK類庫提供的序列化API:

java.io.ObjectOutputStream
表示對象輸出流式撼,其中writeObject(Object obj)方法可以將給定參數(shù)的obj對象進(jìn)行序列化童社,將轉(zhuǎn)換的一連串的字節(jié)序列寫到指定的目標(biāo)輸出流中。
java.io.ObjectInputStream
該類表示對象輸入流著隆,該類下的readObject(Object obj)方法會從源輸入流中讀取字節(jié)序列扰楼,并將它反序列化為一個java對象并返回。
序列化要求:

實現(xiàn)序列化的類對象必須實現(xiàn)了Serializable類或Externalizable類才能被序列化美浦,否則會拋出異常弦赖。

實現(xiàn)java序列化和反序列化的三種方法:

現(xiàn)在要對student類進(jìn)行序列化和反序列化,遵循以下方法:

方法一:若student類實現(xiàn)了serializable接口浦辨,則可以通過objectOutputstream和objectinputstream默認(rèn)的序列化和反序列化方式蹬竖,對非transient的實例變量進(jìn)行序列化和反序列化。

方法二:若student類實現(xiàn)了serializable接口流酬,并且定義了writeObject(objectOutputStream out)和

readObject(objectinputStream in)方法币厕,則可以直接調(diào)用student類的兩種方法進(jìn)行序列化和反序列化。

方法三:若student類實現(xiàn)了Externalizable接口芽腾,則必須實現(xiàn)readExternal(Objectinput in)和writeExternal(Objectoutput out)方法進(jìn)行序列化和反序列化旦装。

JDK類庫中的序列化步驟:

第一步:創(chuàng)建一個輸出流對象,它可以包裝一個輸出流對象摊滔,如:文件輸出流阴绢。

ObjectOutputStream out = new ObjectOutputStream(new fileOutputStream("E:\\JavaXuLiehua\\Student\\Student1.txt"));

第二步:通過輸出流對象的writeObject()方法寫對象

out.writeObject("hollo word");

out.writeObject("happy")

JDK中反序列化操作:

第一步:創(chuàng)建文件輸入流對象

 ObjectInputStream in = new ObjectInputStream(new fileInputStream("E:\\JavaXuLiehua\\Student\\Student1.txt"));

第二步:調(diào)用readObject()方法

 String obj1 = (String)in.readObject();

 String obj2 = (String)in.readObject();

為了保證正確讀取數(shù)據(jù)店乐,對象輸出流寫入對象的順序與對象輸入流讀取對象的順序一致。

Student類序列化和反序列化演示:

1.先創(chuàng)建一個繼承了serializable類的student類

import java.io.Serializable;            //導(dǎo)入io包下的序列化類
 
//創(chuàng)建實現(xiàn)序列化接口的學(xué)生類
public class Student implements Serializable {
    //私有化成員變量
    private String name;
    private  char sex;
    private  int year;
    private  double gpa;
 
    public Student(){   //無參構(gòu)造
    }
    public Student(String name,char sex,int year,double gpa){
        //參數(shù)給屬性賦值
        this.name = name;
        this.sex = sex;
        this.year = year;
        this.gpa = gpa;
    }
 
    //重寫set和get
    public String getName() {
        return name;
    }
 
    public void setName(String name) {
        this.name = name;
    }
 
    public char getSex() {
        return sex;
    }
 
    public void setSex(char sex) {
        this.sex = sex;
    }
 
    public int getYear() {
        return year;
    }
 
    public void setYear(int year) {
        this.year = year;
    }
 
    public double getGpa() {
        return gpa;
    }
 
    public void setGpa(double gpa) {
        this.gpa = gpa;
    }
}

把Student類的對象序列化到txt文件(E:\JavaXuLiehua\Student\Student1.txt)中呻袭,并對文件進(jìn)行反序列化:

import java.io.*;
import java.io.Externalizable;
/*
把student類對象序列化到文件E:\\JavaXuLiehua\\Student\\Student1.txt
 */
public class UserStudent {
    public static void main(String[] args) throws IOException {
        Student st = new Student("Tom",'M',20,3.6);         //實例化student類
        //判斷Student1.txt是否創(chuàng)建成功
        File file = new File("E:\\JavaXuLiehua\\Student\\Student1.txt");
        if(file.exists()) {
            System.out.println("文件存在");
        }else{
            //否則創(chuàng)建新文件
            file.createNewFile();
        }
        try {
            //Student對象序列化過程
            FileOutputStream fos = new FileOutputStream(file);
            ObjectOutputStream oos = new ObjectOutputStream(fos);
            //調(diào)用 ObjectOutputStream 中的 writeObject() 方法 寫對象
            oos.writeObject(st);
            oos.flush();        //flush方法刷新緩沖區(qū)眨八,寫字符時會用,因為字符會先進(jìn)入緩沖區(qū)左电,將內(nèi)存中的數(shù)據(jù)立刻寫出
            fos.close();
            oos.close();
 
            //Student對象反序列化過程
            FileInputStream fis = new FileInputStream(file);
            //創(chuàng)建對象輸入流
            ObjectInputStream ois = new ObjectInputStream(fis);
            //讀取對象
            Student st1 = (Student) ois.readObject();           //會拋出異常(類找不到異常)
            System.out.println("name = " + st1.getName());
            System.out.println("sex = " + st1.getSex());
            System.out.println("year = " + st1.getYear());
            System.out.println("gpa = " + st1.getGpa());
            ois.close();
            fis.close();
        }catch (ClassNotFoundException e){
            e.printStackTrace();
        }
    }
}

查看txt文件廉侧,結(jié)果如下:

 sr JavaxulieHua.Studentd9Q藿Hf D gpaC sexI yearL namet Ljava/lang/String;xp@ 燙燙掏 M   t Tom

可以看出其中的內(nèi)容是不容易閱讀的,只能通過反序列化讀取券腔。

四、transient關(guān)鍵字

transient關(guān)鍵字表示有理的拘泞,被修飾的數(shù)據(jù)不能進(jìn)行序列化

這里不做詳細(xì)介紹纷纫,修改情況如下:

private transient char sex;         //被transient關(guān)鍵字修飾,不參與序列化

運(yùn)行結(jié)果如下:

文件存在
name = Tom
sex =  
year = 20
gpa = 3.6

此時可以看見陪腌,被transient關(guān)鍵字修飾的變量sex并沒有被序列化辱魁,返回了空值。

五诗鸭、Externalizable接口實現(xiàn)序列化與反序列化

Externalizable接口繼承Serializable接口染簇,實現(xiàn)Externalizable接口需要實現(xiàn)readExternal()方法和writeExternal()方法,這兩個方法是抽象方法强岸,對應(yīng)的是serializable接口的readObject()方法和writeObject()方法锻弓,可以理解為把serializable的兩個方法抽象出來。Externalizable沒有serializable的限制蝌箍,static和transient關(guān)鍵字修飾的屬性也能進(jìn)行序列化青灼。

具體代碼實現(xiàn)如下:

復(fù)制對象student命名為student1,在里面重寫writeExternal()方法和readExternal()方法妓盲,如下:

   @Override
    //對抽象方法進(jìn)行重寫
    public void writeExternal(ObjectOutput out) throws IOException{
        out.writeObject(name);
        out.writeObject(sex);
        out.writeObject(year);
        out.writeObject(gpa);
    }
    @Override
    public void readExternal(ObjectInput in) throws IOException, ClassNotFoundException {
        name = (String) in.readObject();
        sex = (char) in.readObject();
        year = (int) in.readObject();
        gpa = (double) in.readObject();
    }

相應(yīng)的測試方法里面調(diào)用這兩種方法的時候杂拨,直接調(diào)用writeObject()方法和readObject()方法即可,重寫的writeExternal()和readExternal()方法會自動執(zhí)行悯衬。

FileOutputStream fos1 = new FileOutputStream(file1);
                ObjectOutputStream oos1 = new ObjectOutputStream(fos1);
                //調(diào)用 ObjectOutputStream 中的 writeObject() 方法 寫對象
                oos1.writeObject(st);       //會自動執(zhí)行重寫的writeExternal()方法
FileInputStream fis1 = new FileInputStream(file1);
                //創(chuàng)建對象輸入流
                ObjectInputStream ois1 = new ObjectInputStream(fis1);
                //讀取對象
                //會自動執(zhí)行readExternal()方法
                Student1 st1 = (Student1) ois1.readObject();           //會拋出異常(類找不到異常)

雖然student1類里的sex屬性被static或transient修飾弹沽,但依舊被序列化,結(jié)果如下:

文件存在
name = Tom
sex = M
year = 20
gpa = 3.6
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末筋粗,一起剝皮案震驚了整個濱河市策橘,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌娜亿,老刑警劉巖役纹,帶你破解...
    沈念sama閱讀 219,188評論 6 508
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異暇唾,居然都是意外死亡促脉,警方通過查閱死者的電腦和手機(jī)辰斋,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,464評論 3 395
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來瘸味,“玉大人宫仗,你說我怎么就攤上這事∨苑拢” “怎么了藕夫?”我有些...
    開封第一講書人閱讀 165,562評論 0 356
  • 文/不壞的土叔 我叫張陵,是天一觀的道長枯冈。 經(jīng)常有香客問我毅贮,道長,這世上最難降的妖魔是什么尘奏? 我笑而不...
    開封第一講書人閱讀 58,893評論 1 295
  • 正文 為了忘掉前任滩褥,我火速辦了婚禮,結(jié)果婚禮上炫加,老公的妹妹穿的比我還像新娘瑰煎。我一直安慰自己,他們只是感情好俗孝,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,917評論 6 392
  • 文/花漫 我一把揭開白布酒甸。 她就那樣靜靜地躺著,像睡著了一般赋铝。 火紅的嫁衣襯著肌膚如雪插勤。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,708評論 1 305
  • 那天革骨,我揣著相機(jī)與錄音饮六,去河邊找鬼。 笑死苛蒲,一個胖子當(dāng)著我的面吹牛卤橄,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播臂外,決...
    沈念sama閱讀 40,430評論 3 420
  • 文/蒼蘭香墨 我猛地睜開眼窟扑,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了漏健?” 一聲冷哼從身側(cè)響起嚎货,我...
    開封第一講書人閱讀 39,342評論 0 276
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎蔫浆,沒想到半個月后殖属,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,801評論 1 317
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡瓦盛,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,976評論 3 337
  • 正文 我和宋清朗相戀三年洗显,在試婚紗的時候發(fā)現(xiàn)自己被綠了外潜。 大學(xué)時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,115評論 1 351
  • 序言:一個原本活蹦亂跳的男人離奇死亡挠唆,死狀恐怖处窥,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情玄组,我是刑警寧澤滔驾,帶...
    沈念sama閱讀 35,804評論 5 346
  • 正文 年R本政府宣布,位于F島的核電站俄讹,受9級特大地震影響哆致,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜患膛,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,458評論 3 331
  • 文/蒙蒙 一摊阀、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧剩瓶,春花似錦驹溃、人聲如沸城丧。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,008評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽亡哄。三九已至枝缔,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間蚊惯,已是汗流浹背愿卸。 一陣腳步聲響...
    開封第一講書人閱讀 33,135評論 1 272
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留截型,地道東北人趴荸。 一個月前我還...
    沈念sama閱讀 48,365評論 3 373
  • 正文 我出身青樓,卻偏偏與公主長得像宦焦,于是被迫代替她去往敵國和親发钝。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,055評論 2 355

推薦閱讀更多精彩內(nèi)容