匿名类上的NotSerializableException

时间:2013-07-23 08:07:51

标签: java serialization hadoop interface anonymous-class

我有一个过滤项目的界面:

public interface KeyValFilter extends Serializable {
    public static final long serialVersionUID = 7069537470113689475L;
    public boolean acceptKey(String iKey, Iterable<String> iValues);
    public boolean acceptValue(String iKey, String value);
}

以及包含KeyValFilter类型成员的类。

public class KeyValFilterCollector extends KeyValCollectorSkeleton {
    private static final long serialVersionUID = -3364382369044221888L;
    KeyValFilter filter;
    public KeyValFilterCollector(KeyValFilter filter) {
        this.filter=filter;
    }
}

当我尝试使用实施KeyValFilterCollector的匿名类启动KeyValFilter时:

new KeyValFilterCollector(new KeyValFilter() {
        private static final long serialVersionUID = 7069537470113689475L;
        public boolean acceptKey(String iKey, Iterable<String> iValues) {
            for (String value : iValues) {
                if (value.startsWith("1:"))
                        return true;
            }
            return false;
        }
        public boolean acceptValue(String iKey, String value) {
            return value.startsWith("0:");
        }
});

我得到一个例外:Exception in thread "main" java.io.NotSerializableException

如何创建我编写Serializable的匿名类?

3 个答案:

答案 0 :(得分:27)

Joshua Bloch在他的书Effective Java, 2nd Edition中写道,第74项:

  

内部课程不应实施Serializable 。它们使用编译器生成的合成字段来存储对封闭实例的引用,并存储来自封闭范围的局部变量的值。这些字段如何对应于类定义是未指定的,匿名和本地类的名​​称也是如此。因此,内部类的默认序列化形式是错误定义的。但是,静态成员类可以实现Serializable

答案 1 :(得分:11)

通常,序列化匿名类时遇到的问题是封闭类不可序列化(并且作者没有意识到序列化匿名类涉及序列化其封闭类)。

匿名类是非静态内部类。这意味着它有一个隐藏字段,它引用了封闭类的实例。当您使用new KeyValFilter(){ ... }创建它时,如果没有明确限定它(例如something.new KeyValFilter(){ ... }),则隐式使用this作为封闭类的实例(就像您this.new KeyValFilter(){ ... }一样)。因此,在序列化匿名类时,需要序列化其所有字段,其中一个是封闭类的实例,然后必须是可序列化的。

如果您不需要使用封闭类的任何字段或方法,则应使用静态内部类。 (但它不能匿名或在方法中定义。)

答案 2 :(得分:0)

您可以声明匿名类可序列化,但只有所有字段都可序列化时,该类才真正可序列化。

参见示例:

public static void main(String[] args) throws Exception {
    Object myObj = new Serializable() {
        private static final long serialVersionUID = 1L;
        private String str = "something";
        private Object ns = new Object(){};
    };
    ByteArrayOutputStream baos = new ByteArrayOutputStream();
    ObjectOutputStream oos = new ObjectOutputStream(baos);
    oos.writeObject(myObj);
    oos.close();
    System.out.println("Success!");
}

如果您对该行发表评论

private Object ns = new Object(){};

代码成功完成,否则抛出NotSerializableException