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

在android中為什么要序列化?

答:在android中傳遞對象的時候,如果直接傳遞的話,接受方無法識別,因此需要序列化,將對象轉換成流的形式傳遞。在另一方利用反序列化解析出來。(自己理解的,如有錯誤請高手指出)

什么情況下需要序列化?

a)當你想把內存中的對象寫入到硬盤的時候;

b)當你想用套接字在網絡上傳送對象的時候;

c)當你想通過RMI傳輸對象的時候;

再稍微解釋一下:a)比如說你的內存不夠用了,那計算機就要將內存里面的一部分對象暫時的保存到硬盤中,等到要用的時候再讀入到內存中,硬盤的那部分存儲空間就是所謂的虛擬內存。在比如過你要將某個特定的對象保存到文件中,我隔幾天在把它拿出來用,那么這時候就要實現Serializable接口;

b)在進行java的Socket編程的時候,你有時候可能要傳輸某一類的對象,那么也就要實現Serializable接口;最常見的你傳輸一個字符串,它是JDK里面的類,也實現了Serializable接口,所以可以在網絡上傳輸。

c)如果要通過遠程的方法調用(RMI)去調用一個遠程對象的方法,如在計算機A中調用另一台計算機B的對象的方法,那么你需要通過JNDI服務獲取計算機B目標對象的引用,將對象從B傳送到A,就需要實現序列化接口。

在NewsListActivity.java中

Intent intent = new Intent(NewsListActivity.this, NewsInfoActivity.class);

intent.putExtra("ItemState", item);

NewsListActivity.this.startActivity(intent);

在NewsInfoActivity.java中

if(intent.getExtras() != null){item = (RSSItem)intent.getExtras().getSerializable("ItemState");

}

這里要求RSSItem類必須能序列化,即實現Serializable接口

我的RSSItem繼承RSSObject類,而RSSObject類沒有實現Serializable接口

public class RSSItem extends RSSObject implements Serializable

現在問題出現了,沒有報編譯錯誤,也沒出現運行時錯誤,但就是NewsInfoActivity拿到的item的很多屬性為null

解決:父類RSSObject必須實現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; }

從上面的例子我們可以看到,除了需要實現Serialzable接口外,一個可序列化的類和一個普通類沒有什么大的區別。不過我們還是有一些特別的東西需要注意的。

2)屬性 serialVersionUID

這個屬性是一個私有的靜態final屬性,一般剛接觸序列化的人會忽略這個屬性,因為這個屬性不是必須的。這個屬性主要是為了保證一個可序列 化類在不同的 Java編譯器中,能保證相同的版本號,這樣保證當這個類在不同的JVM中進行序列化與反序列化時不會出現InvalidClassException異 常。

3)屬性與序列化

那么我們再考慮另一個問題,是不是一個類實現了Serializable之后就可以看成是可序列化的類呢?答案是不行,實際上一個類是否可序 列化還需要看這個類的屬性,在Java規范中,一個類是否能序列化,不但取決於這個類是否實現Serializable接口,還取決於這個類中的屬性是否 可序列化。在上面的例子里,一共有三個屬性,兩個是String對象,一個是int類型的屬性,實際上,String類是可序列化的(繼承了 Serializable 接口且它的屬性都是可序列化的),而像int這樣的基本數據類型在Java中被看成是可序列化的,因此我們可以確認上面的這個類是一個可序列化的類。那么 現在我們已經創建了一個可序列化類,接下去的問題是怎么使用這個類,對它進行序列化與反序列化操作?

4)ObjectOutputStream 和 ObjectInputStream類

Jdk提供了兩個IO流類進行序列化和反序列化操作,其中ObjectOutputStream中的writeObject方法對一個對象進 行序列化工作;而ObjectInputStrem中的readObject方法則負責發序列化的操作。下面的例子完整的顯示了一個類的序列化和反序列化 操作。

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");

//創建ObjectOutputStream對象,准備序列化對象s

ObjectOutputStream oos = new ObjectOutputStream(

new FileOutputStream("abc"));

//調用writeObject將對象進行序列化,存儲在文件abc中。

oos.writeObject;

oos.flush();

oos.close();

//創建ObjectInputStream對象,准備從文件abc中反序列化SerialClass對象

ObjectInputStream ois = new ObjectInputStream(

new FileInputStream("abc"));

//調用readObject將存儲在文件abc中的字節流反序列化為SerialClass對象。

s = (SerialClass) ois.readObject();

System.out.println(s.getA());

System.out.println(s.getB());

System.out.println(s.getC());

}

}

執行程序,最后的結果應該是:

10

Hello

World

好了,序列化的基礎知識就講到這里。接下來我們看看繼承對於序列化的影響。

二、繼承對序列化的影響

我們現在把上面的例子做點變換,變成如下的形式。

1)首先創建一個Interface。

package serialtest;

public interface SuperInterface

{

public int getA();

public String getB();

public void setA(int a);

public void setB(String b);

}

2)創建一個抽象類實現SuperInterface接口,注意,這個類沒有實現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,同時它也實現了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;}

}

這時候我們在運行Test,將會發現結果和第一節的例子不一樣了,這時候結果將變成:

0

null

world

而導致這個結果的原因就在AbSuperClass上,因為AbSuperClass沒有實現Serializable接口,所以它不可被序 列化;但 SerialClass由於實現了Serializable接口而成為一個可序列化的類,這時候,屬性c因為是SerialClass的類所以c的值在序 列化時將被保存,而屬性a和b是從AbSuperClass中繼承而來,他們因為AbSuperClass的緣故而導致了它們的值不能在序列化是被保存。

關於這一點,我在Java文檔中也得到了證實,在Java doc中明確指出,如果一個類繼承了一個非Serializable類時,如果想在序列化中保存父類的屬性,則需要實現額外的代碼顯式地存儲父類的屬性值。

最后再回到本文的初衷,誠然,這篇文章是以對象的序列化為主的,但最后我又要回到一個比較古老的話題上,那就是在軟件開發的時候,繼承到底該用到什么一種程度?畢竟,濫用繼承對整個系統的影響將是深遠的。

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

Java的序列化機制是通過在運行時判斷類的serialVersionUID來驗證版本一致性的。在進行反序列化時,JVM會把傳來的字節流中的serialVersionUID與本地相應實體(類)的serialVersionUID進行比較,如果相同就認為是一致的,可以進行反序列化,否則就會出現序列化版本不一致的異常。

有兩種生成方式: 一個是默認的1L,比如:private static final long serialVersionUID = 1L;

一個是根據類名、接口名、成員方法及屬性等來生成一個64位的哈希字段,比如: private static final long serialVersionUID = xxxxL;

當你一個類實現了Serializable接口,如果沒有定義serialVersionUID,Eclipse會提供這個 提示功能告訴你去定義 。在Eclipse中點擊類中warning的圖標一下,Eclipse就會 自動給定兩種生成的方式。如果不想定義它,在Eclipse的設置中也 可以把它關掉的,設置如下: Window ==> Preferences ==> Java ==> Compiler ==> Error/Warnings ==> Potential programming problems 將Serializable class without serialVersionUID的warning改成ignore即可。

如果你沒有考慮到兼容性問題時,就把它關掉,不過有這個功能是好的,只要任何類別實現了Serializable這個接口的話,如果沒有加入serialVersionUID,Eclipse都會給你warning提示,這個serialVersionUID為了讓該類別Serializable向后兼容。如果你的類Serialized存到硬盤上面后,可是后來你卻更改了類別的field(增加或減少或改名),當你Deserialize時,就會出現Exception的,這樣就會造成不兼容性的問題。但當serialVersionUID相同時,它就會將不一樣的field以type的預設值Deserialize,可避開不兼容性問題。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值