3

これが私の小さなクラスです:

import java.io.Serializable;
public abstract class SerializableCallback extends Callback
implements Serializable {
    private static final long serialVersionUID = 4544768712188843966L;
    public abstract void handleMessage(Message msg);
}

これがさらに小さな親Callbackです:

public abstract class Callback {
    public abstract void handleMessage(Message msg);
}

そして、これが私のテストです:

public void testSerialization() throws IOException, ClassNotFoundException {
    SerializableCallback c = new SerializableCallback() {
        private static final long serialVersionUID = -4852385037064234702L;
        @Override
        public void handleMessage(Message msg) {
            callbackMethod();
        }
    };

    FileOutputStream fos = new FileOutputStream(FILE);
    ObjectOutputStream out = new ObjectOutputStream(fos);
    out.writeObject(c); // fails
    out.close();

    FileInputStream fis = new FileInputStream(FILE);
    ObjectInputStream in = new ObjectInputStream(fis);
    Object object = in.readObject();
    @SuppressWarnings("unused")
    SerializableCallback d = (SerializableCallback) object;
}

private void callbackMethod() {}

テストではNotSerializableException、コメントで示された行にが表示されます。これが確かに引き起こされないいくつかの事柄です:

  1. シリアル化可能な宣言がありません
  2. シリアル化できないフィールド:フィールドはまったくありません
  3. 最も近いシリアライズ不可能な親型の非表示の非引数コンストラクター

では、何例外を引き起こしますか?

4

3 に答える 3

6

クラスには引数なしのコンストラクターがありません。thisこれには、外部クラスの引数を1つ取るコンストラクターがあります。testSerialization()を作成した場合static、問題が解決する可能性があります。

しかし、あなたの当面の本当の問題は、ネストクラスに外部クラスへの参照があり、外部クラスがシリアル化できないことだと思います。

于 2012-10-16T14:58:12.443 に答える
2

Peterの回答に対するコメント(コメントには長すぎる)にさらに対処するためSerializableCallbackに、テストメソッドの匿名クラスは技術的には内部クラスです。

  • 非静的メソッドで宣言された場合、匿名クラスは本質的に非静的内部クラスです。
  • 静的メソッドで宣言された場合、匿名クラスは本質的に静的内部クラスです。

これが、切り替えが機能した理由staticです。静的クラスを作成した匿名クラスが作成されたため、テストクラスへの暗黙の参照が保持されなくなり、シリアル化可能になりました。

非静的レベルで宣言された匿名クラスと内部クラスは、常にそれを囲むクラスへの参照を保持することに注意してください。callbackMethod()そうでなければ、匿名クラスがそれを宣言していないので、あなたはあなたの匿名クラスを呼び出すことができなかっただろう。

ObjectOutputStream匿名をシリアル化しようとすると、コールバックテストクラスのSerializableCallback両方への参照が保持されているため、コールバックとテストクラスの両方をシリアル化しようとしました。これは、このクラスをシリアル化しようとするようなものでした。SerializableCallback

// Declared in its own file
public class MySerializableCallback extends SerializableCallback {
    private static final long serialVersionUID = -4852385037064234702L;

    // Equiv to Callback.this in an inner class
    private final CallbackTest test;

    public MySerializableCallback(CallbackTest test) {
        this.test = test;
    }

    @Override
    public void handleMessage(Message msg) {
        test.callbackMethod();
    }
}

このクラスをシリアル化しようとした場合、CallbackTestおそらくシリアル化できないため、失敗することは明らかです。

于 2012-10-16T15:46:01.790 に答える
1

これらのケースを確認してください

これらの条件下では、シリアル化は失敗します。

  • インスタンス変数の削除。

  • インスタンス変数のタイプを変更します。

  • インスタンス変数を非一時的から一時的に変更します。

  • インスタンス変数を非静的から静的に変更します。

  • クラスを階層の上下に移動します。

于 2012-10-16T14:59:43.170 に答える