Android,androidsdk
Serializable
public class Test implements Serializable { private static final long serialVersionUID = 1L; public static int staticVar = 5; public static void main(String[] args) { try { //初始時staticVar為5 ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("result.obj")); out.writeObject(new Test()); out.close(); //序列化後修改為10 Test.staticVar = 10; ObjectInputStream oin = new ObjectInputStream(new FileInputStream( "result.obj")); Test t = (Test) oin.readObject(); oin.close(); //再讀取,通過t.staticVar列印新的值 System.out.println(t.staticVar); } catch (FileNotFoundException e) { e.printStackTrace(); } catch (IOException e) { e.printStackTrace(); } catch (ClassNotFoundException e) { e.printStackTrace(); } }}
最後的輸出是 10
一個子類實現了 Serializable 介面,它的父類都沒有實現 Serializable 介面,序列化該子類對象,然後還原序列化後輸出父類定義的某變數的數值,該變數數值與序列化時的數值不同。
要想將父類對象也序列化,就需要讓父類也實現Serializable 介面。如果父類不實現的話的,就 需要有預設的無參的建構函式。如果你考慮到這種序列化的情況,在父類無參建構函式中對變數進行初始化,否則的話,父類變數值都是預設聲明的值,如 int 型的預設是 0,string 型的預設是 null。
我們熟悉使用 Transient 關鍵字可以使得欄位不被序列化,那麼還有別的方法嗎?根據父類對象序列化的規則,我們可以將不需要被序列化的欄位抽取出來放到父類中,子類實現 Serializable 介面,父類不實現,根據父類序列化規則,父類的欄位資料將不被序列化。
ObjectOutputStream out = new ObjectOutputStream( new FileOutputStream("result.obj")); Test test = new Test(); //試圖將對象兩次寫入檔案 out.writeObject(test); out.flush(); System.out.println(new File("result.obj").length()); out.writeObject(test); out.close(); System.out.println(new File("result.obj").length()); ObjectInputStream oin = new ObjectInputStream(new FileInputStream( "result.obj")); //從檔案依次讀出兩個檔案 Test t1 = (Test) oin.readObject(); Test t2 = (Test) oin.readObject(); oin.close(); //判斷兩個引用是否指向同一個對象 System.out.println(t1 == t2);
對同一對象兩次寫入檔案,列印出寫入一次對象後的儲存大小和寫入兩次後的儲存大小,然後從檔案中還原序列化出兩個對象,比較這兩個對象是否為同一對象。一般的思維是,兩次寫入對象,檔案大小會變為兩倍的大小,還原序列化時,由於從檔案讀取,產生了兩個對象,判斷相等時應該是輸入 false 才對,但是。。。
android.os.BadParcelableException: ClassNotFoundException when unmarshalling
public Config config;public RowView(Parcel in){ type = in.readString(); interfaceUrl = in.readString(); size = in.readInt(); config = in.readParcelable(null);}
報錯的語句即為config = in.readParcelable(null);
根據android文檔介紹:
readParcelable (ClassLoader loader)
loader A ClassLoader from which to instantiate the Parcelable object, or null for the default class loader.即loader為空白時系統會採取預設的class loader。
Android有兩種不同的classloaders:framework classloader和apk classloader,其中framework classloader知道怎麼載入android classes,apk classloader知道怎麼載入you code,apk classloader繼承自framework classloader,所以也知道怎麼載入android classes。
在應用剛啟動時,預設class loader是apk classloader,但在系統記憶體不足應用被系統回收會再次啟動,這個預設class loader會變為framework classloader了,所以對於自己的類會報ClassNotFoundException。
將config = in.readParcelable(null);改為config = in.readParcelable(Config.class.getClassLoader());
Config.class.getClassLoader()即為apk classloader, 其中Config.class可以改為你程式中自己寫的任意類,因為他們同樣指向apk loader。
試著改為config = in.readParcelable(Activity.class.getClassLoader());你會發現依然ClassNotFoundException因為Activity.class.getClassLoader()指向的是framework classloader
我是天王蓋地虎的分割線
參考:http://www.ibm.com/developerworks/cn/java/j-lo-serial/index.html