java序列化與反序列化

java序列化與反序列化

對(duì)象序列化是一種持久化技術(shù),廣泛運(yùn)用于網(wǎng)絡(luò)傳輸、RMI等場(chǎng)景中。java對(duì)象存在于JVM運(yùn)行時(shí),然而有時(shí)期望即使JVM關(guān)閉了也可以保存當(dāng)前對(duì)象以備將來(lái)重新使用或者給其他JVM使用,為解決類似問(wèn)題可以采用持久化技術(shù)。java中對(duì)象的序列化就是將對(duì)象轉(zhuǎn)化為字符序列存放在磁盤或內(nèi)存中,反序列化則相反。對(duì)象要想序列化,要求相應(yīng)的類實(shí)現(xiàn)Serializable接口。注意,序列化保存的只是對(duì)象的狀態(tài),并不包含方法和靜態(tài)成員變量。下面是實(shí)現(xiàn)序列化的一個(gè)小例子:

public class People implements Serializable {

    private static final long serialVersionUID = -2189866613532876533L;

    public String mName;

    public int mAge;

    public static String mSchool = "WUST";

    public People(String name, int age) {
        mName = name;
        mAge = age;
    }

    public static void setSchool(String mSchool) {
        People.mSchool = mSchool;
    }

    @Override
    public String toString() {
        return "People{" +
                "mName='" + mName + '\'' +
                ", mAge=" + mAge +
                '}';
    }

    public static void main(String[] args) {
        People people = new People("ldg", 22);

        File file = new File("D:\\Users\\lidegui371\\Desktop\\People");

        try {
            ObjectOutputStream out = new ObjectOutputStream(new FileOutputStream(file));
            System.out.println(People.mSchool);
            out.writeObject(people);

            People.setSchool("武漢科技大學(xué)");

            ObjectInputStream in = new ObjectInputStream(new FileInputStream(file));
            People p1 = (People) in.readObject();
            System.out.println(p1);
            System.out.println(People.mSchool);
        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }
}

輸出為:WUST People{mName='ldg', mAge=22} 武漢科技大學(xué)

類中的serialVersionUID用來(lái)標(biāo)識(shí)反序列的類與序列化的類是否為同一個(gè)類,假如沒有聲明serialVersionUID,系統(tǒng)在序列化和反序列時(shí)會(huì)調(diào)用相應(yīng)的算法生成這個(gè)標(biāo)識(shí),一旦這個(gè)類有一點(diǎn)修改都會(huì)導(dǎo)致這個(gè)標(biāo)識(shí)不一樣,所以在將之前序列化對(duì)象反序列化時(shí)會(huì)因?yàn)?code>serialVersionUID不一樣而出錯(cuò)。虛擬機(jī)是否允許反序列化不僅取決于類路徑和功能代碼是否一致,還取決于這兩個(gè)類的序列化 ID 是否一致。如果serialVersionUID一樣,即使類有改動(dòng)也可以成功地反序列化(如果類添加了字段,值為java初始值,比如int=0,String=null;如果字段減少,則不影響沒改變的其他字段)。

transient所修飾的字段可以在序列化時(shí)不被序列化到文件中,在反序列化時(shí)該字段被賦予初始值。如果想讓transient修飾的字段也可以進(jìn)行序列化與反序列化可以在類中定義writeObjectreadObject方法,自己控制序列化,如果類中沒有這兩個(gè)方法,則系統(tǒng)會(huì)調(diào)用ObjectOutputStream中的defaultWriteObject方法和ObjectInputStream中的defaultReadObject方法。

在序列化的時(shí)候,private字段的數(shù)據(jù)是以明文的形式存放的,這在網(wǎng)絡(luò)傳輸中及其不安全,所以可以在類中定義readObjectwriteObject方法實(shí)現(xiàn)序列化數(shù)據(jù)模糊化,比如:

private void writeObject(ObjectOutputStream out) throws IOException {

        // 第一種寫法
        System.out.println("未加密前的年齡:" + mAge);
        ObjectOutputStream.PutField field = out.putFields();
        field.put("mAge", mAge >> 1);
        field.put("mName", mName);
        out.writeFields();
        System.out.println("加密完成");

//        // 第二種寫法
//        mAge = mAge >> 2;
//        out.defaultWriteObject();
    }

    private void readObject(ObjectInputStream in) throws IOException, ClassNotFoundException {

        // 第一種寫法
        ObjectInputStream.GetField field = in.readFields();
        mName = (String) field.get("mName", "");
        mAge = field.get("mAge", 0);
        System.out.println("讀出來(lái)的年齡:" + mAge);
        mAge = mAge << 1;
        System.out.println("解密完成");

//        // 第二種寫法
//        in.defaultReadObject();
//        mAge = mAge << 2;
    }

由上可知writeObjectreadObject方法可以自定義控制序列化。控制序列化還可以使用writeReplacereadResolve,只不過(guò)使用了這兩個(gè)方法后是將序列化對(duì)象或反序列化的對(duì)象給替換了。比如有一個(gè)People類,它在writeReplace方法中返回了一個(gè)PeopleProxy的代理類,那么序列化的對(duì)象就變成了PeopleProxy,序列化與反序列化時(shí)與PeopleProxy類中相關(guān)的方法有關(guān),所以可以利用這個(gè)方法舊類序列化為新版本。readResolve則相反,將反序列化的數(shù)據(jù)序列化為指定的對(duì)象,這個(gè)方法可以用來(lái)保護(hù)性恢復(fù)單例。這四者的調(diào)用順序?yàn)椋?code>writeReplace—>writeObject—>readObject—>readResolve。需要注意的是,當(dāng)這個(gè)類調(diào)用了writeReplace后,序列化的控制就轉(zhuǎn)到了這個(gè)方法返回的那個(gè)對(duì)象的類中了。

在JAVA中,序列化時(shí)除了實(shí)現(xiàn)Serializable還可以實(shí)現(xiàn)Externalizable接口,它繼承于Serializable并聲明了兩個(gè)abstract方法:writeExternalreadExternal,所以它要求手動(dòng)實(shí)現(xiàn)序列化與反序列化,用法和SerializablewriteObjectreadObject一樣。Externalizable在效率上比Serializable要高,但如果不需要自定義序列化過(guò)程,一般使用Serializable。

在android開發(fā)中,除了使用Serializable還可以使用Parcelable實(shí)現(xiàn)對(duì)象序列化。Serializable使用起來(lái)開銷較大,通過(guò)IO流寫入到磁盤和傳輸?shù)骄W(wǎng)絡(luò),android設(shè)計(jì)的Parcelable是為了在程序內(nèi)不同組件間和android跨進(jìn)程而設(shè)計(jì)的一種序列化方式,它是通過(guò)IBinder通信的消息的載體,攜帶的數(shù)據(jù)僅存在內(nèi)存中,由于內(nèi)存的讀寫速度比磁盤的要快,所以在內(nèi)存間的數(shù)據(jù)傳輸推薦使用Parcelable,但因其在持久化和網(wǎng)絡(luò)傳輸上操作復(fù)雜,在這方面推薦使用Serializable

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
平臺(tái)聲明:文章內(nèi)容(如有圖片或視頻亦包括在內(nèi))由作者上傳并發(fā)布,文章內(nèi)容僅代表作者本人觀點(diǎn),簡(jiǎn)書系信息發(fā)布平臺(tái),僅提供信息存儲(chǔ)服務(wù)。
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 229,836評(píng)論 6 540
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異,居然都是意外死亡,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 99,275評(píng)論 3 428
  • 文/潘曉璐 我一進(jìn)店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人,你說(shuō)我怎么就攤上這事?!?“怎么了?”我有些...
    開封第一講書人閱讀 177,904評(píng)論 0 383
  • 文/不壞的土叔 我叫張陵,是天一觀的道長(zhǎng)。 經(jīng)常有香客問(wèn)我,道長(zhǎng),這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,633評(píng)論 1 317
  • 正文 為了忘掉前任,我火速辦了婚禮,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 72,368評(píng)論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 55,736評(píng)論 1 328
  • 那天,我揣著相機(jī)與錄音,去河邊找鬼。 笑死,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,740評(píng)論 3 446
  • 文/蒼蘭香墨 我猛地睜開眼,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起,我...
    開封第一講書人閱讀 42,919評(píng)論 0 289
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 49,481評(píng)論 1 335
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 41,235評(píng)論 3 358
  • 正文 我和宋清朗相戀三年,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 43,427評(píng)論 1 374
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,968評(píng)論 5 363
  • 正文 年R本政府宣布,位于F島的核電站,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 44,656評(píng)論 3 348
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 35,055評(píng)論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,348評(píng)論 1 294
  • 我被黑心中介騙來(lái)泰國(guó)打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 52,160評(píng)論 3 398
  • 正文 我出身青樓,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 48,380評(píng)論 2 379

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