1. 程式人生 > >Android序列化問題與思考

Android序列化問題與思考

今天再來談談Android中的物件序列化,你瞭解多少呢? ## 序列化指的是什麼?有什麼用 **序列化**指的是講物件變成有序的`位元組流`,變成位元組流之後才能進行傳輸儲存等一系列操作。 **反序列化**就是序列化的`相反操作`,也就是把序列化生成的位元組流轉為我們記憶體的物件。 ## 介紹下Android中兩種序列化介面 ### Serializable 是`Java`提供的一個序列化介面,是一個空介面,專門為物件提供序列化和反序列化操作。具體使用如下: ```java public class User implements Serializable { private static final long serialVersionUID=519067123721561165l; private int id; public int getId() { return id; } public void setId(int id) { this.id = id; } } ``` 實現`Serializable`介面,宣告一個`serialVersionUID`。 到這裡可能有人就問了,不對啊,平時沒有這個`serialVersionUID`啊。沒錯,`serialVersionUID`不是必須的,因為不寫的話,系統會自動生成這個變數。它有什麼用呢?當序列化的時候,系統會把當前類的`serialVersionUID`寫入序列化的檔案中,當反序列化的時候會去檢測這個`serialVersionUID`,看他是否和當前類的`serialVersionUID`一致,一樣則可以正常反序列化,如果不一樣就會報錯了。 所以這個`serialVersionUID`就是序列化和反序列化過程中的一個標識,代表一致性。不加的話會有什麼影響?如果我們序列化後,改動了這個類的某些成員變數,那麼`serialVersionUID`就會改變,這時候再拿之前序列化的資料來反序列化就會報錯。所以如果我們手動指定`serialVersionUID`就能保證最大限度來恢復資料。 `Serializable`的實質其實是是把Java物件序列化為二進位制檔案,然後就能在程序之間傳遞,並且用於網路傳輸或者本地儲存等一系列操作,因為他的本質就儲存了檔案。可以看看原始碼: ```java private void writeObject0(Object obj, boolean unshared) throws IOException { ... try { Object orig = obj; Class cl = obj.getClass(); ObjectStreamClass desc; desc = ObjectStreamClass.lookup(cl, true); if (obj instanceof Class) { writeClass((Class) obj, unshared); } else if (obj instanceof ObjectStreamClass) { writeClassDesc((ObjectStreamClass) obj, unshared); // END Android-changed: Make Class and ObjectStreamClass replaceable. } else if (obj instanceof String) { writeString((String) obj, unshared); } else if (cl.isArray()) { writeArray(obj, desc, unshared); } else if (obj instanceof Enum) { writeEnum((Enum) obj, desc, unshared); } else if (obj instanceof Serializable) { writeOrdinaryObject(obj, desc, unshared); } else { if (extendedDebugInfo) { throw new NotSerializableException( cl.getName() + "\n" + debugInfoStack.toString()); } else { throw new NotSerializableException(cl.getName()); } } } ... } private void writeOrdinaryObject(Object obj, ObjectStreamClass desc, boolean unshared) throws IOException { ... try { desc.checkSerialize(); //寫入二進位制檔案,普通物件開頭的魔數0x73 bout.writeByte(TC_OBJECT); //寫入對應的類的描述符,見底下原始碼 writeClassDesc(desc, false); handles.assign(unshared ? null : obj); if (desc.isExternalizable() && !desc.isProxy()) { writeExternalData((Externalizable) obj); } else { writeSerialData(obj, desc); } } finally { if (extendedDebugInfo) { debugInfoStack.pop(); } } } public long getSerialVersionUID() { // 如果沒有定義serialVersionUID,序列化機制就會呼叫一個函式根據類內部的屬性等計算出一個hash值 if (suid == null) { suid = AccessController.doPrivileged( new Privileg