匿名类上的NotSerializableException
我有一个过滤项目的界面:
public interface KeyValFilter extends Serializable{ public static final long serialVersionUID = 7069537470113689475L; public boolean acceptKey(String iKey, Iterable 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; }
当我尝试使用实现KeyValFilter的匿名类启动KeyValFilterCollector时:
new KeyValFilterCollector(new KeyValFilter(){ private static final long serialVersionUID = 7069537470113689475L; public boolean acceptKey(String iKey, Iterable 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:线程“main”中的exceptionjava.io.NotSerializableException如何创建我编写Serializable的匿名类?
Joshua Bloch在他的书Effective Java,第2版 ,第74项中写道:
内部类不应该实现
Serializable
。 它们使用编译器生成的合成字段来存储对封闭实例的引用,并存储来自封闭范围的局部变量的值。 这些字段如何对应于类定义是未指定的,匿名和本地类的名称也是如此。 因此, 内部类的默认序列化forms是未定义的 。 但是, 静态成员类可以实现Serializable
。
通常,序列化匿名类时遇到的问题是封闭类不可序列化(并且作者没有意识到序列化匿名类涉及序列化其封闭类)。
匿名类是非静态内部类 。 这意味着它有一个隐藏字段,它引用了封闭类的实例。 当你使用new KeyValFilter(){ ... }
创建它时,没有明确限定它(例如something.new KeyValFilter(){ ... }
),那么this
被隐式地用作封闭类的实例(就像你做了this.new KeyValFilter(){ ... }
)。 因此,在序列化匿名类时,需要序列化其所有字段,其中一个是封闭类的实例,然后必须是可序列化的。
如果您不需要使用封闭类的任何字段或方法,则应使用静态内部类。 (但它不能匿名或在方法中定义。)
您可以声明匿名类可序列化,但只有所有字段都可序列化时,该类才真正可序列化。
看例子:
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
。