没有字段的抽象类上的NotSerializableException

时间:2012-10-16 14:53:58

标签: java serialization

这是我的小班:

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. 最接近的非序列化父类型的不可见非arg构造函数
  4. 那么 会导致异常?

3 个答案:

答案 0 :(得分:6)

您的类没有no-arg构造函数。它有一个构造函数,它接受一个参数,即外部类的this。如果您创建了testSerialization()static,它可能会解决问题。

但我怀疑你的直接真正的问题是你的nest类有一个对外部类的引用而外部类不是Serializable。

答案 1 :(得分:1)

检查这些案例

在这些条件下,序列化失败:

  • 删除实例变量。

  • 更改实例变量的类型。

  • 将实例变量从非瞬态更改为瞬态。

  • 将实例变量从非静态更改为静态。

  • 在层次结构中上下移动班级。

答案 2 :(得分:1)

为了进一步阐述您对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可能不是可序列化的。