Java 没有字段的抽象类上的NotSerializableException

Java 没有字段的抽象类上的NotSerializableException,java,serialization,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); }

这是我的小班级:

import java.io.Serializable;
public abstract class SerializableCallback extends Callback
implements Serializable {
    private static final long serialVersionUID = 4544768712188843966L;
    public abstract void handleMessage(Message msg);
}
下面是它的更小的父级回调:

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() {}
测试在注释指示的行上给了我一个
notserializableeexception
。这里有几件事是绝对不会引起这种情况的:

  • 缺少可序列化声明
  • 不可序列化字段:根本没有字段
  • 最近的不可序列化父类型的不可见非参数构造函数

  • 那么是什么导致了异常呢?

    您的类没有无参数构造函数。它有一个构造函数,它接受一个参数,即外部类的
    this
    。如果您使用testSerialization()
    static
    ,则可能会解决此问题

    但是我怀疑您的直接真正问题是,您的嵌套类引用了外部类,并且外部类不可序列化。

    检查这些情况

    在这些情况下,序列化失败:

    • 删除实例变量

    • 更改实例变量的类型

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

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

    • 在层次结构中上下移动类


    为了进一步说明您对Peter答案的评论(评论太长了),测试方法中的匿名
    SerializableCallback
    类在技术上是一个内部类

    • 在非静态方法中声明时,匿名类本质上是非静态内部类
    • 在静态方法中声明时,匿名类本质上是静态内部类
    这就是为什么切换到
    静态
    有效的原因。由于它使您创建的匿名类成为静态类,因此它不再包含对测试类的隐式引用,因此它是可序列化的

    请记住,在非静态级别声明的匿名类和内部类始终包含对封闭类的引用。如果没有,您就无法在匿名类中调用
    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
    可能无法序列化。

    Kumar,您应该知道不要用代码格式突出显示“Removing”之类的随机词:“Removing”不是代码。这三个类没有嵌套,因此没有“outer”类。请解释一下为什么会有你提到的构造函数?无论如何,使
    testSerialization()
    static
    解决了这个问题。当您的方法不是
    static
    时,您的嵌套类将成为一个内部类,它隐式地引用了
    OuterClass。无论您是否需要它,这个
    作为字段。它通常被称为
    此$0
    。要将此值(以及您可能使用的任何其他
    final
    局部变量)传递给构造函数,“默认”构造函数必须采用附加参数。顺便说一句:如果创建名为
    this$0
    的字段,它将创建名为
    this$0$
    this$0$
    等的字段;)谢谢你的耐心和彻底!