java - 為什麼Serializable中定義的Class 不能序列化?
欧阳克
欧阳克 2017-06-30 09:56:37
0
2
1182
Serialized 類別中的

Fields 本身必須是可序列化的或瞬態的,即使該類別從未明確序列化或反序列化。這是因為在負載下,大多數J2EE 應用程式框架都會將物件刷新到磁碟,而具有非瞬態、不可序列化資料成員的所謂可序列化物件可能會導致程式崩潰,並為攻擊者打開大門。

此規則在非可序列化欄位以及非私有欄位(因為可以在外部為它們分配非序列化值)以及在類別內為它們分配非序列化類型時引發集合欄位問題。

不合規程式碼範例

雷雷
欧阳克
欧阳克

温故而知新,可以为师矣。 博客:www.ouyangke.com

全部回覆(2)
扔个三星炸死你

一個物件序列化時,依照Java預設的序列化規則,物件內的所有成員都要序列化,也就是說,這些Class都必須實作Serializable。

所以,你有兩種改法,一是Address實作Serializable接口,二是對Person中的address成員加上transient標記,這樣該成員就不會被序列化進去。

typecho

如果 address 成員需要進行序列化的話,則Address類別也需要實作Serializable介面。
如果 address 成員不需要進行序列化的話,可以加上transient關鍵字,則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
}

當然還有其他方式:
例如實作Externalizable接口,重寫readExternal(ObjectInput in)和writeExternal(ObjectOutput out)方法。
還有一個替代實作Externalizable介面方法,還是實作Serializable接口,加入writeObject(ObjectOutputStream obs)和readObject(ObjectInputStream ois)方法。


再說說為什麼Address一定要實作Serializable,或是加上transient關鍵字Person才能進行序列化?
先看看不做處理,使用 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,就可以進行序列化,否則會拋出NotSerializableException。且在序列化物件時,不僅會序列化目前物件本身,還會對該物件引用的其它物件也進行序列化。

熱門教學
更多>
最新下載
更多>
網站特效
網站源碼
網站素材
前端模板
關於我們 免責聲明 Sitemap
PHP中文網:公益線上PHP培訓,幫助PHP學習者快速成長!