这是一个简化的课程:
class Foo implements Serializable {
private static final long serialVersionUID = 1L;
private Integer id;
private Set<Foo> children;
public Foo( Integer id ) {
if( id == null ) {
throw new IllegalArgumentException( );
}
this.id = id;
this.children = new HashSet<Foo>( 16 );
}
@Override public int hashCode( ) {
return id.hashCode( );
}
...
}
如您所见,它包含一组自身,并使用其id
属性生成哈希。但是当对象具有自引用循环时,我遇到了一个问题:
当对象被反序列化时,处理首先跟随子对象到最深的对象,然后向后构建。这通常很好,但如果一个对象在其children
集中包含一个较高的对象,它就会中断:当它试图将此对象添加到其HashSet时,它会调用hashCode
,但是id
尚未为该对象加载,因此它与NullPointerException崩溃。
(我花了很长时间来跟踪它!)
所以我的问题是:我可以控制序列化的顺序吗?我需要在{/ em> id
之前children
序列化(和反序列化)。
答案 0 :(得分:1)
您的分析似乎是正确的。您应该实现自定义序列化逻辑。假设id是唯一的,请考虑以下内容:
答案 1 :(得分:0)
我遵循了jdev的建议,并且(经过一些研究)使用Externalizable接口实现了我自己的序列化,如下所示:
class Foo implements Externalizable {
/**
* DO NOT USE THIS CONSTRUCTOR! This only exists for Externalizable
*/
public Foo( ) {
id = null;
children = null;
}
@Override public void writeExternal( final ObjectOutput o ) throws IOException {
o.writeInt( id.intValue( ) );
o.writeObject( children );
}
@SuppressWarnings( "unchecked" )
@Override public void readExternal( final ObjectInput o ) throws IOException, ClassNotFoundException {
id = Integer.valueOf( o.readInt( ) );
children = (Set<Foo>) o.readObject( );
}
// rest of code as before
}
我唯一的抱怨是它现在需要一个公共的无参数构造函数,但我可以忍受(至少这是一个内部API)。
现在所有事情都按照正确的顺序完成,我没有问题反序列化。