android中的序列化問題(Serializable小結(jié))

  • 在android中為什么要序列化传轰?

答:在android中傳遞對象的時(shí)候谷婆,如果直接傳遞的話辽聊,接受方無法識(shí)別跟匆,因此需要序列化通砍,將對象轉(zhuǎn)換成流的形式傳遞。在另一方利用反序列化解析出來迹冤。(自己理解的泡徙,如有錯(cuò)誤請高手指出)

  • 什么情況下需要序列化膜蠢?

a)當(dāng)你想把內(nèi)存中的對象寫入到硬盤的時(shí)候;
b)當(dāng)你想用套接字在網(wǎng)絡(luò)上傳送對象的時(shí)候礁竞;
c)當(dāng)你想通過RMI傳輸對象的時(shí)候杉辙;

再稍微解釋一下:
a)比如說你的內(nèi)存不夠用了,那計(jì)算機(jī)就要將內(nèi)存里面的一部分對象暫時(shí)的保存到硬盤中枫绅,等到要用的時(shí)候再讀入到內(nèi)存中硼端,硬盤的那部分存儲(chǔ)空間就是所謂的虛擬內(nèi)存。在比如過你要將某個(gè)特定的對象保存到文件中珍昨,我隔幾天在把它拿出來用,那么這時(shí)候就要實(shí)現(xiàn)Serializable接口兔毙;

b)在進(jìn)行java的Socket編程的時(shí)候兄春,你有時(shí)候可能要傳輸某一類的對象,那么也就要實(shí)現(xiàn)Serializable接口哑姚;最常見的你傳輸一個(gè)字符串,它是JDK里面的類叙量,也實(shí)現(xiàn)了Serializable接口绞佩,所以可以在網(wǎng)絡(luò)上傳輸。

c)如果要通過遠(yuǎn)程的方法調(diào)用(RMI)去調(diào)用一個(gè)遠(yuǎn)程對象的方法析既,如在計(jì)算機(jī)A中調(diào)用另一臺(tái)計(jì)算機(jī)B的對象的方法谆奥,那么你需要通過JNDI服務(wù)獲取計(jì)算機(jī)B目標(biāo)對象的引用酸些,將對象從B傳送到A檐蚜,就需要實(shí)現(xiàn)序列化接口。

在NewsListActivity.java中

<pre style="box-sizing: border-box; outline: 0px; margin: 0px 0px 24px; padding: 8px; position: relative; font-family: Consolas, Inconsolata, Courier, monospace; white-space: pre-wrap; word-wrap: break-word; overflow-x: auto; font-size: 14px; line-height: 22px; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
    Intent intent = new Intent(NewsListActivity.this, NewsInfoActivity.class);
    intent.putExtra("ItemState", item);
    NewsListActivity.this.startActivity(intent);
</pre>

在NewsInfoActivity.java中

<pre style="box-sizing: border-box; outline: 0px; margin: 0px 0px 24px; padding: 8px; position: relative; font-family: Consolas, Inconsolata, Courier, monospace; white-space: pre-wrap; word-wrap: break-word; overflow-x: auto; font-size: 14px; line-height: 22px; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
    if(intent.getExtras() != null){
       item = (RSSItem)intent.getExtras().getSerializable("ItemState");
    }
</pre>

這里要求RSSItem類必須能序列化,即實(shí)現(xiàn)Serializable接口

我的RSSItem繼承RSSObject類咳短,而RSSObject類沒有實(shí)現(xiàn)Serializable接口

<pre style="box-sizing: border-box; outline: 0px; margin: 0px 0px 24px; padding: 8px; position: relative; font-family: Consolas, Inconsolata, Courier, monospace; white-space: pre-wrap; word-wrap: break-word; overflow-x: auto; font-size: 14px; line-height: 22px; color: rgb(0, 0, 0); font-style: normal; font-variant-ligatures: normal; font-variant-caps: normal; font-weight: 400; letter-spacing: normal; orphans: 2; text-align: start; text-indent: 0px; text-transform: none; widows: 2; word-spacing: 0px; -webkit-text-stroke-width: 0px; background-color: rgb(255, 255, 255); text-decoration-style: initial; text-decoration-color: initial;">
    public class RSSItem extends RSSObject implements Serializable
</pre>

現(xiàn)在問題出現(xiàn)了咙好,沒有報(bào)編譯錯(cuò)誤,也沒出現(xiàn)運(yùn)行時(shí)錯(cuò)誤嘹悼,但就是NewsInfoActivity拿到的item的很多屬性為null

解決:父類RSSObject必須實(shí)現(xiàn)Serializable接口层宫,就沒問題了。

http://www.cjsdn.net/post/view?bid=2&id=192312&sty=1&tpg=5&age=0

一限匣、序列化簡介

在這里我先簡要介紹一下和序列化相關(guān)的一些概念膛腐,如果你覺得自己對序列化已經(jīng)比較熟悉,那么跳過這一節(jié)哲身,直接看下一節(jié)內(nèi)容。
序列化是Java中的一個(gè)非常重要的特性怔揩,通過序列化機(jī)制粱腻,我們可以將Java的對象變成流宠进,或者存儲(chǔ)在硬盤中,或者通過網(wǎng)絡(luò)傳輸給網(wǎng)絡(luò)的其他用戶材蹬。而序列化在RMI,EJB中都有應(yīng)用昆庇,可以說是構(gòu)成J2EE的一個(gè)重要的技術(shù)闸溃。

  • 1)Serializable接口

如果想讓一個(gè)類可被序列化,那么這個(gè)類必須實(shí)現(xiàn)Serializable接口表蝙,這個(gè)接口本身沒有任何方法和屬性乓旗,它的作用只是為了標(biāo)示一個(gè)類可以被序列化,這一個(gè)特性好像在Java里用的比較多欲诺,比如克隆也是采用了相同的機(jī)制扰法。
因此,如果我們想創(chuàng)建一個(gè)可以被序列化的類塞颁,我們可以像下面的代碼一樣做祠锣。

import java.io.Serializable; 
public class SerialClass implements Serializable 
{ 
private static final long serialVersionUID = -190734710746841476L; 
private String c; 
public int a; 
public String b; 
public int getA(){return a;} 
public String getB(){return b;} 
public void setA(int a){this.a = a;} 
public void setB(String b){this.b = b;} 
public String getC(){return c; } 
public void setC(String c){this.c = c; } 

從上面的例子我們可以看到,除了需要實(shí)現(xiàn)Serialzable接口外蓬推,一個(gè)可序列化的類和一個(gè)普通類沒有什么大的區(qū)別澡腾。不過我們還是有一些特別的東西需要注意的。

  • 2)屬性 serialVersionUID

這個(gè)屬性是一個(gè)私有的靜態(tài)final屬性毅糟,一般剛接觸序列化的人會(huì)忽略這個(gè)屬性澜公,因?yàn)檫@個(gè)屬性不是必須的。這個(gè)屬性主要是為了保證一個(gè)可序列 化類在不同的 Java編譯器中迹辐,能保證相同的版本號糊渊,這樣保證當(dāng)這個(gè)類在不同的JVM中進(jìn)行序列化與反序列化時(shí)不會(huì)出現(xiàn)InvalidClassException異 常渺绒。

  • 3)屬性與序列化

那么我們再考慮另一個(gè)問題菱鸥,是不是一個(gè)類實(shí)現(xiàn)了Serializable之后就可以看成是可序列化的類呢?答案是不行殷绍,實(shí)際上一個(gè)類是否可序 列化還需要看這個(gè)類的屬性鹊漠,在Java規(guī)范中主到,一個(gè)類是否能序列化登钥,不但取決于這個(gè)類是否實(shí)現(xiàn)Serializable接口娶靡,還取決于這個(gè)類中的屬性是否 可序列化。在上面的例子里塔鳍,一共有三個(gè)屬性轮纫,兩個(gè)是String對象,一個(gè)是int類型的屬性蜡感,實(shí)際上郑兴,String類是可序列化的(繼承了 Serializable 接口且它的屬性都是可序列化的),而像int這樣的基本數(shù)據(jù)類型在Java中被看成是可序列化的叽粹,因此我們可以確認(rèn)上面的這個(gè)類是一個(gè)可序列化的類却舀。那么 現(xiàn)在我們已經(jīng)創(chuàng)建了一個(gè)可序列化類,接下去的問題是怎么使用這個(gè)類辆脸,對它進(jìn)行序列化與反序列化操作螃诅?

  • 4)ObjectOutputStream 和 ObjectInputStream類

Jdk提供了兩個(gè)IO流類進(jìn)行序列化和反序列化操作,其中ObjectOutputStream中的writeObject方法對一個(gè)對象進(jìn) 行序列化工作倘是;而ObjectInputStrem中的readObject方法則負(fù)責(zé)發(fā)序列化的操作袭艺。下面的例子完整的顯示了一個(gè)類的序列化和反序列化 操作。

package serialtest; 
import java.io.FileInputStream; 
import java.io.FileOutputStream; 
import java.io.ObjectInputStream; 
import java.io.ObjectOutputStream; 
public class TestClass { 

public static void main(String[] args) throws Exception { 
    SerialClass s = new SerialClass(); 
    s.setA(10); 
    s.setB("hello"); 
    s.setC("world"); 

    //創(chuàng)建ObjectOutputStream對象瘤睹,準(zhǔn)備序列化對象s 
    ObjectOutputStream oos = new ObjectOutputStream( 
                  new FileOutputStream("abc")); 

    //調(diào)用writeObject將對象進(jìn)行序列化默蚌,存儲(chǔ)在文件abc中苇羡。 
    oos.writeObject; 
    oos.flush(); 
    oos.close(); 

    //創(chuàng)建ObjectInputStream對象鼻弧,準(zhǔn)備從文件abc中反序列化SerialClass對象 
    ObjectInputStream ois = new ObjectInputStream( 
                  new FileInputStream("abc")); 

    //調(diào)用readObject將存儲(chǔ)在文件abc中的字節(jié)流反序列化為SerialClass對象攘轩。 
    s = (SerialClass) ois.readObject(); 
    System.out.println(s.getA()); 
    System.out.println(s.getB()); 
    System.out.println(s.getC()); 
    } 
} 

執(zhí)行程序码俩,最后的結(jié)果應(yīng)該是:

10 
Hello 
World

好了,序列化的基礎(chǔ)知識(shí)就講到這里笨篷。接下來我們看看繼承對于序列化的影響瓣履。

二、繼承對序列化的影響

我們現(xiàn)在把上面的例子做點(diǎn)變換冕臭,變成如下的形式燕锥。

  • 1)首先創(chuàng)建一個(gè)Interface。
package serialtest; 
public interface SuperInterface 
{ 
public int getA(); 
public String getB(); 
public void setA(int a); 
public void setB(String b); 
} 
  • 2)創(chuàng)建一個(gè)抽象類實(shí)現(xiàn)SuperInterface接口托慨,注意暇榴,這個(gè)類沒有實(shí)現(xiàn)Serializable接口。
package serialtest; 
public abstract class AbsSuperClass implements SuperInterface 
{ 
public int a; 
public String b; 
public int getA() {return a;} 
public String getB(){return b; } 
public void setA(int a) {this.a = a;} 
public void setB(String b) {this.b = b;} 
} 
  • 3)SerialClass類繼承了AbSuperClass窟感,同時(shí)它也實(shí)現(xiàn)了Serializable接口歉井。
package serialtest; 
import java.io.Serializable; 
public class SerialClass extends AbsSuperClass implements Serializable 
{ 
private static final long serialVersionUID = -190734710746841476L; 
private String c; 
public String getC(){return c; } 
public void setC(String c) {this.c = c;} 
} 

這時(shí)候我們在運(yùn)行Test哩至,將會(huì)發(fā)現(xiàn)結(jié)果和第一節(jié)的例子不一樣了蜜自,這時(shí)候結(jié)果將變成:

0 
null 
world 

而導(dǎo)致這個(gè)結(jié)果的原因就在AbSuperClass上,因?yàn)锳bSuperClass沒有實(shí)現(xiàn)Serializable接口箭阶,所以它不可被序 列化;但 SerialClass由于實(shí)現(xiàn)了Serializable接口而成為一個(gè)可序列化的類嘹叫,這時(shí)候诈乒,屬性c因?yàn)槭荢erialClass的類所以c的值在序 列化時(shí)將被保存,而屬性a和b是從AbSuperClass中繼承而來喂饥,他們因?yàn)锳bSuperClass的緣故而導(dǎo)致了它們的值不能在序列化是被保存肠鲫。
關(guān)于這一點(diǎn),我在Java文檔中也得到了證實(shí)集侯,在Java doc中明確指出帜消,如果一個(gè)類繼承了一個(gè)非Serializable類時(shí),如果想在序列化中保存父類的屬性泡挺,則需要實(shí)現(xiàn)額外的代碼顯式地存儲(chǔ)父類的屬性值。

最后再回到本文的初衷娄猫,誠然,這篇文章是以對象的序列化為主的媳溺,但最后我又要回到一個(gè)比較古老的話題上,那就是在軟件開發(fā)的時(shí)候扯躺,繼承到底該用到什么一種程度蝎困?畢竟,濫用繼承對整個(gè)系統(tǒng)的影響將是深遠(yuǎn)的澎埠。

Java中serialVersionUID的解釋serialVersionUID作用: 序列化時(shí)為了保持版本的兼容性始藕,即在版本升級時(shí)反序列化仍保持對象的唯一性氮趋。

Java的序列化機(jī)制是通過在運(yùn)行時(shí)判斷類的serialVersionUID來驗(yàn)證版本一致性的凭峡。在進(jìn)行反序列化時(shí)决记,JVM會(huì)把傳來的字節(jié)流中的serialVersionUID與本地相應(yīng)實(shí)體(類)的serialVersionUID進(jìn)行比較,如果相同就認(rèn)為是一致的索昂,可以進(jìn)行反序列化扩借,否則就會(huì)出現(xiàn)序列化版本不一致的異常。

有兩種生成方式:

一個(gè)是默認(rèn)的1L康谆,比如:private static final long serialVersionUID = 1L;
一個(gè)是根據(jù)類名嫉到、接口名、成員方法及屬性等來生成一個(gè)64位的哈希字段孽锥,比如: private static final long serialVersionUID = xxxxL;

當(dāng)你一個(gè)類實(shí)現(xiàn)了Serializable接口细层,如果沒有定義serialVersionUID,Eclipse會(huì)提供這個(gè) 提示功能告訴你去定義 盛撑。在Eclipse中點(diǎn)擊類中warning的圖標(biāo)一下捧搞,Eclipse就會(huì) 自動(dòng)給定兩種生成的方式。如果不想定義它陌僵,在Eclipse的設(shè)置中也 可以把它關(guān)掉的创坞,設(shè)置如下: Window ==> Preferences ==> Java ==> Compiler ==> Error/Warnings ==> Potential programming problems 將Serializable class without serialVersionUID的warning改成ignore即可受葛。

如果你沒有考慮到兼容性問題時(shí)偎谁,就把它關(guān)掉巡雨,不過有這個(gè)功能是好的席函,只要任何類別實(shí)現(xiàn)了Serializable這個(gè)接口的話,如果沒有加入serialVersionUID正蛙,Eclipse都會(huì)給你warning提示营曼,這個(gè)serialVersionUID為了讓該類別Serializable向后兼容。如果你的類Serialized存到硬盤上面后锻全,可是后來你卻更改了類別的field(增加或減少或改名)录煤,當(dāng)你Deserialize時(shí),就會(huì)出現(xiàn)Exception的部翘,這樣就會(huì)造成不兼容性的問題响委。但當(dāng)serialVersionUID相同時(shí),它就會(huì)將不一樣的field以type的預(yù)設(shè)值Deserialize赘风,可避開不兼容性問題。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末荸哟,一起剝皮案震驚了整個(gè)濱河市鞍历,隨后出現(xiàn)的幾起案子肪虎,更是在濱河造成了極大的恐慌,老刑警劉巖刑枝,帶你破解...
    沈念sama閱讀 212,718評論 6 492
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異装畅,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)像云,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 90,683評論 3 385
  • 文/潘曉璐 我一進(jìn)店門苫费,熙熙樓的掌柜王于貴愁眉苦臉地迎上來双抽,“玉大人,你說我怎么就攤上這事铐维∩鞣疲” “怎么了?”我有些...
    開封第一講書人閱讀 158,207評論 0 348
  • 文/不壞的土叔 我叫張陵睬棚,是天一觀的道長解幼。 經(jīng)常有香客問我,道長底靠,這世上最難降的妖魔是什么特铝? 我笑而不...
    開封第一講書人閱讀 56,755評論 1 284
  • 正文 為了忘掉前任鲫剿,我火速辦了婚禮,結(jié)果婚禮上灵莲,老公的妹妹穿的比我還像新娘。我一直安慰自己请琳,他們只是感情好俄精,可當(dāng)我...
    茶點(diǎn)故事閱讀 65,862評論 6 386
  • 文/花漫 我一把揭開白布竖慧。 她就那樣靜靜地躺著逆屡,像睡著了一般。 火紅的嫁衣襯著肌膚如雪魏蔗。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 50,050評論 1 291
  • 那天廓鞠,我揣著相機(jī)與錄音床佳,去河邊找鬼榄审。 笑死,一個(gè)胖子當(dāng)著我的面吹牛搁进,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播篮撑,決...
    沈念sama閱讀 39,136評論 3 410
  • 文/蒼蘭香墨 我猛地睜開眼赢笨,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了茧妒?” 一聲冷哼從身側(cè)響起左冬,我...
    開封第一講書人閱讀 37,882評論 0 268
  • 序言:老撾萬榮一對情侶失蹤拇砰,失蹤者是張志新(化名)和其女友劉穎狰腌,沒想到半個(gè)月后,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體琼腔,經(jīng)...
    沈念sama閱讀 44,330評論 1 303
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡丹莲,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 36,651評論 2 327
  • 正文 我和宋清朗相戀三年尸诽,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片洲赵。...
    茶點(diǎn)故事閱讀 38,789評論 1 341
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡商蕴,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出究恤,到底是詐尸還是另有隱情,我是刑警寧澤抄腔,帶...
    沈念sama閱讀 34,477評論 4 333
  • 正文 年R本政府宣布理张,位于F島的核電站,受9級特大地震影響悟耘,放射性物質(zhì)發(fā)生泄漏织狐。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 40,135評論 3 317
  • 文/蒙蒙 一移迫、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧邪媳,春花似錦、人聲如沸迅涮。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,864評論 0 21
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽顿肺。三九已至渣蜗,卻和暖如春,著一層夾襖步出監(jiān)牢的瞬間讼昆,已是汗流浹背骚烧。 一陣腳步聲響...
    開封第一講書人閱讀 32,099評論 1 267
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留赃绊,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 46,598評論 2 362
  • 正文 我出身青樓运敢,卻偏偏與公主長得像忠售,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個(gè)殘疾皇子稻扬,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 43,697評論 2 351

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