【java】【android】序列化Serializable和繼承

來源:互聯網
上載者:User

今天在android的實驗上,碰到個問題,花了1個多小時查出問題並解決。

這個問題比較隱蔽,不瞭解的話會浪費很多時間。

先看代碼:

在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介面,就沒問題了。

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

一、序列化簡介

在這裡我先簡要介紹一下和序列化相關的一些概念,如果你覺得自己對序列化已經比較熟悉,那麼跳過這一節,直接看下一節內容。

序列化是Java中的一個非常重要的特性,通過序列化機制,我們可以將Java的對象變成流,或者儲存在硬碟中,或者通過網路傳輸給網路的其他使用者。而序列化在RMI,EJB中都有應用,可以說是構成J2EE的一個重要的技術。

1)Serializable介面

如果想讓一個類可被序列化,那麼這個類必須實現Serializable介面,這個介面本身沒有任何方法和屬性,它的作用只是為了標示一個類可以被序列化,這一個特性好像在Java裡用的比較多,比如複製也是採用了相同的機制。

因此,如果我們想建立一個可以被序列化的類,我們可以像下面的代碼一樣做。

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; }

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

2)屬性 serialVersionUID

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

3)屬性與序列化

那麼我們再考慮另一個問題,是不是一個類實現了Serializable之後就可以看成是可序列化的類呢?答案是不行,實際上一個類是否可序列化還需要看這個類的屬性,在Java規範中,一個類是否能序列化,不但取決於這個類是否實現Serializable介面,還取決於這個類中的屬性是否可序列化。在上面的例子裡,一共有三個屬性,兩個是String對象,一個是int類型的屬性,實際上,String類是可序列化的(繼承了Serializable 介面且它的屬性都是可序列化的),而像int這樣的基礎資料型別 (Elementary Data Type)在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類時,如果想在序列化中儲存父類的屬性,則需要實現額外的代碼顯式地儲存父類的屬性值。

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

聯繫我們

該頁面正文內容均來源於網絡整理,並不代表阿里雲官方的觀點,該頁面所提到的產品和服務也與阿里云無關,如果該頁面內容對您造成了困擾,歡迎寫郵件給我們,收到郵件我們將在5個工作日內處理。

如果您發現本社區中有涉嫌抄襲的內容,歡迎發送郵件至: info-contact@alibabacloud.com 進行舉報並提供相關證據,工作人員會在 5 個工作天內聯絡您,一經查實,本站將立刻刪除涉嫌侵權內容。

A Free Trial That Lets You Build Big!

Start building with 50+ products and up to 12 months usage for Elastic Compute Service

  • Sales Support

    1 on 1 presale consultation

  • After-Sales Support

    24/7 Technical Support 6 Free Tickets per Quarter Faster Response

  • Alibaba Cloud offers highly flexible support services tailored to meet your exact needs.