java - 為什么Serializable中定義的Class 不能序列化?
問題描述
Fields in a Serializable class must themselves be either Serializable or transient even if the class is never explicitly serialized or deserialized. That’s because under load, most J2EE application frameworks flush objects to disk, and an allegedly Serializable object with non-transient, non-serializable data members could cause program crashes, and open the door to attackers.This rule raises an issue on non-Serializable fields, and on collection fields when they are not private (because they could be assigned non-Serializable values externally), and when they are assigned non-Serializable types within the class.Noncompliant Code Examplepublic class Address { //...}public class Person implements Serializable { private static final long serialVersionUID = 1905122041950251207L; private String name; private Address address; // Noncompliant; Address isn’t serializable}
問題解答
回答1:一個對象序列化時,按照J(rèn)ava默認(rèn)的序列化規(guī)則,對象內(nèi)的所有成員都要序列化,也就是說,這些Class都必須實(shí)現(xiàn)Serializable。
所以,你有兩種改法,一是Address實(shí)現(xiàn)Serializable接口,二是對Person中的address成員加上transient標(biāo)記,這樣該成員就不會被序列化進(jìn)去。
回答2:如果 address 成員需要進(jìn)行序列化的話,則Address類也需要實(shí)現(xiàn)Serializable接口。如果 address 成員不需要進(jìn)行序列化的話,可以加上transient關(guān)鍵字,則address成員不做序列化操作,值為null。如下:
public class Person implements Serializable { private static final long serialVersionUID = 1905122041950251207L; private String name; private transient Address address; // Noncompliant; Address isn’t serializable}
當(dāng)然還有其他方式:比如實(shí)現(xiàn)Externalizable接口,重寫readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法。還有一個替代實(shí)現(xiàn)Externalizable接口方法,還是實(shí)現(xiàn)Serializable接口,添加writeObject(ObjectOutputStream obs)和readObject(ObjectInputStream ois)方法。
再說說為什么Address一定要實(shí)現(xiàn)Serializable,或者加上transient關(guān)鍵字Person才能進(jìn)行序列化?先看看不做處理,使用 ObjectOutputStream 來持久化對象,拋出的異常
Exception in thread 'main' java.io.NotSerializableException
看ObjectOutputStream源碼:
/** * Underlying writeObject/writeUnshared implementation. */ private void writeObject0(Object obj, boolean unshared)throws IOException { //...... // remaining cases 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());} }} finally { depth--; bout.setBlockDataMode(oldMode);} }
從此可知, 如果被寫對象類型是String、Array、Enum、Serializable,就可以進(jìn)行序列化,否則將拋出NotSerializableException。且在序列化對象時,不僅會序列化當(dāng)前對象本身,還會對該對象引用的其它對象也進(jìn)行序列化。
相關(guān)文章:
1. 網(wǎng)頁爬蟲 - python爬蟲翻頁問題,請問各位大神我這段代碼怎樣翻頁,還有價格要登陸后才能看到,應(yīng)該怎么解決2. python如何不改動文件的情況下修改文件的 修改日期3. python 正則表達(dá)式提取4. 算法 - python 給定一個正整數(shù)a和一個包含任意個正整數(shù)的 列表 b,求所有<=a 的加法組合5. javascript - 微信h5發(fā)送圖文信息,部分設(shè)備點(diǎn)擊“發(fā)送”按鈕時沒反應(yīng),問題較難重現(xiàn),如何能找到可能存在問題的點(diǎn)?6. javascript - 微信小程序里怎么把頁面轉(zhuǎn)成圖片分享7. 大家好,請問在python腳本中怎么用virtualenv激活指定的環(huán)境?8. python - 求一個在def中可以實(shí)現(xiàn)調(diào)用本def滿足特定條件continue效果的方法(標(biāo)題說不太清楚,請見題內(nèi)描述)9. javascript - JS用ajax爬取百度外賣店家信息10. python - Pycharm調(diào)試代碼進(jìn)行列表遍歷時,如何直接賦值指定元素
