簡體   English   中英

不可序列化父類的可序列化子類

[英]Serializable subclass of non-serializable parent class

我正在通過序列化 android/java 中的 Location 子類遇到磚牆

位置不可序列化。 我有一個名為 FALocation 的第一個子類,它沒有任何實例變量。 我已經聲明它是可序列化的。

然后我有一個名為 Waypoint 的第二個類,如下所示:

public class Waypoint extends FALocation implements Serializable {

    /**
     * 
     */
    private static final long serialVersionUID = 1L;

    /* Class variables *******************************************************/
    private static int CLASS_VERSION=1; //Used to version parcels

    /* Instance variables ****************************************************/
    private transient String type=DataHelper.PT_TYPE_US;
    private transient String country; 
    private transient String name=null;
    private transient String description=null;
    private transient int elevation = 0;
    private transient int population = 0; // Afterthought, added to match the DB structure

    /* Constructors **********************************************************/    
    public Waypoint() {
        super();
    }

    public Waypoint(double lat, double lon, String name, String description) {
        super(lat, lon);
        this.setName(name);
        this.setDescription(description);
    }

    public Waypoint(Location l) {
        super(l);
    }

    public Waypoint(String provider) {
        super(provider);
    }


    /* Implementing serializable */
    private void writeObject(java.io.ObjectOutputStream out) throws IOException {
        Log.v("DroidFA", "Serialising \"%s\" (v%d).", Waypoint.class.getSimpleName(), CLASS_VERSION);
        out.writeInt(CLASS_VERSION);

        out.writeObject(type);
        out.writeObject(country);
        out.writeObject(name);
        out.writeObject(description);
        out.writeInt(elevation);
        out.writeInt(population);
    }

    private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException {

        int serialClassVersion = in.readInt();
        Log.v("DroidFA", "Deserialising \"%s\" (v%d).", Waypoint.class.getSimpleName(),serialClassVersion);

        type = (String) in.readObject();
        country = (String) in.readObject();
        name = (String) in.readObject();
        description = (String) in.readObject();
        elevation = in.readInt();
        population = in.readInt();
    }
}

序列化工作正常。

反序列化產生跟隨異常(leg 對象包含一個航點):

10-05 13:50:35.259: WARN/System.err(7867): java.io.InvalidClassException: android.location.Location; IllegalAccessException
10-05 13:50:35.267: WARN/System.err(7867):     at java.io.ObjectInputStream.resolveConstructorClass(ObjectInputStream.java:2010)
10-05 13:50:35.267: WARN/System.err(7867):     at java.io.ObjectInputStream.readNewObject(ObjectInputStream.java:2095)
10-05 13:50:35.267: WARN/System.err(7867):     at java.io.ObjectInputStream.readNonPrimitiveContent(ObjectInputStream.java:929)
10-05 13:50:35.267: WARN/System.err(7867):     at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2285)
10-05 13:50:35.278: WARN/System.err(7867):     at java.io.ObjectInputStream.readObject(ObjectInputStream.java:2240)
10-05 13:50:35.278: WARN/System.err(7867):     at com.droidfa.navigation.Leg.readObject(Leg.java:262)
.../...

是否絕對有必要對 Location 進行序列化? 也許您可以將其標記為瞬態,並在反序列化對象后動態獲取它。 無論如何,來自文檔):

Q:如果類A沒有實現Serializable但是子類B實現了Serializable,那么B序列化時A類的字段會被序列化嗎?

A:只寫出和恢復Serializable對象的字段。 僅當對象具有將初始化不可序列化超類型的字段的無參數構造函數時,才可以恢復該對象。 如果子類可以訪問超類的狀態,它可以實現 writeObject 和 readObject 來保存和恢復該狀態。

因此,如果子類可以訪問其不可序列化的超類的字段,則它可以使用 writeObject 和 readObject 協議來實現序列化。 否則,將有無法序列化的字段。

看起來 Location 沒有公共/受保護的無參數構造函數。 需要這樣的構造函數才能使其可用於子類中的序列化。

http://download.oracle.com/javase/6/docs/api/java/io/Serializable.html說:

為了允許不可序列化類的子類型被序列化,子類型可能負責保存和恢復超類型的公共、受保護和(如果可訪問)包字段的狀態。 僅當它擴展的類具有可訪問的無參數構造函數來初始化類的狀態時,子類型才可能承擔此責任。 如果不是這種情況,則聲明類 Serializable 是錯誤的。 該錯誤將在運行時檢測到。

與序列化規范中的話相同:

Serializable 類必須執行以下操作: ... 可以訪問其第一個不可序列化超類的無參數構造函數

這將解釋為什么您只在反序列化中遇到問題,因為在序列化期間自然不會調用構造函數。

沒有可訪問的構造函數失敗的小例子:

public class A {
    public A(String some) {};
    private A() {} //as protected or public everything would work
}

public class B extends A implements Serializable {
    public B() {
        super("");
    }
    //these doesn't really matter
    //private void writeObject(java.io.ObjectOutputStream out) throws IOException {  }
    //private void readObject(java.io.ObjectInputStream in) throws IOException, ClassNotFoundException { }
}

public class BSerializer {

    public static void main(String ... args) throws Exception {
        B b = new B();

        ByteArrayOutputStream baos = new ByteArrayOutputStream();
        ObjectOutputStream oos = new ObjectOutputStream(baos);
        oos.writeObject(b);
        ByteArrayInputStream bais = new ByteArrayInputStream(baos.toByteArray());
        ObjectInputStream ois = new ObjectInputStream(bais);
        B deserialized = (B) ois.readObject();   //InvalidClassException
    }
}

暫無
暫無

聲明:本站的技術帖子網頁,遵循CC BY-SA 4.0協議,如果您需要轉載,請注明本站網址或者原文地址。任何問題請咨詢:yoyou2525@163.com.

 
粵ICP備18138465號  © 2020-2024 STACKOOM.COM