可以重写方法ObjectOutputStream.writeStreamHeader()
以在数据头前添加或附加数据。但是,如果该数据基于传递给派生类的构造函数的参数,如:
public class MyObjectOutputStream extends ObjectOutputStream {
public MyObjectOutputStream( int myData, OutputStream out ) throws IOException {
super( out );
m_myData = myData;
}
protected void writeStreamHeader() throws IOException {
write( m_myData ); // WRONG: m_myData not initialized yet
super.writeStreamHeader();
}
private final int m_myData;
}
它无效,因为在super()
初始化m_myData
调用super()
之前调用了writeStreamHeader()
。我能想到解决这个问题的唯一方法是使用ThreadLocal
之类的:
public class MyObjectOutputStream extends ObjectOutputStream {
public MyObjectOutputStream( int myData, OutputStream out ) throws IOException {
super( thunk( myData, out ) );
}
protected void writeStreamHeader() throws IOException {
write( m_myData.get().intValue() );
super.writeStreamHeader();
}
private static OutputStream thunk( int myData, OutputStream out ) {
m_myData.set( myData );
return out;
}
private static final ThreadLocal<Integer> m_myData = new ThreadLocal<Integer>();
}
这似乎有效,但有更好(不那么笨重)的方式吗?
答案 0 :(得分:3)
有一种解决此类问题的通用方法。创建类和内部类,并在外部作用域中引用变量。 (注意,这仅适用于-target 1.4
或greter,这是当前版本的javac中的默认设置。使用-target 1.3
,您将获得NPE。)
public static ObjectOutputStream newInstance(
final int myData, final OutputStream out
) throws IOException {
return new ObjectOutputStream(out) {
@Override
protected void writeStreamHeader() throws IOException {
write(myData);
super.writeStreamHeader();
}
};
}
但是,在构建ObjectOuputStream
之前将数据写出来可能更容易。
答案 1 :(得分:1)
从构造函数中调用非final方法通常是个坏主意(出于你提出的原因)。
您是否可以在不扩展ObjectOutputStream的情况下实现自定义序列化?我正在考虑流组成。例如,您可以通过在ObjectOutputStream执行之前将标头写入底层OutputStream来添加标头。这显然不能在ObjectOutputStream的子类中完成,但可以从外部轻松完成。
out.write(myExtraHeader);
ObjectOutputStream oos = new ObjectOutputStream(out);
如果你愿意,你可以将这一切完美地包装在ObjectOutput接口后面,就像Stu Thompson在他的回答中所建议的那样,这样它就可以像对待ObjectOutputStream一样向外看。
更新
查看ObjectDutputStream的JavaDocs和源代码,有第二个(受保护的)构造函数,它不会调用writeStreamHeader()
。
但是,此构造函数也不会初始化其他内部结构。引用文档, 它旨在“用于完全重新实现ObjectOutputStream的子类 不必分配这个ObjectOutputStream实现所使用的私有数据“。在这种情况下,它还会调用其他一些方法,例如”writeObjectOverride“.Messy ......
答案 2 :(得分:1)
public class MyObjectOutputStream extends ObjectOutputStream {
private boolean initalized = false;
private final int m_myData;
protected MyObjectOutputStream(int myData, OutputStream out) throws IOException, SecurityException {
super(out);
m_myData = myData;
initalized = true;
writeStreamHeader();
}
protected void writeStreamHeader() throws IOException {
if(!initalized){
return;
}
write( m_myData );
super.writeStreamHeader();
}
}
修改强>
或者,正如Thilo所建议的那样,它可以写成:
public class MyObjectOutputStream extends ObjectOutputStream {
private final int m_myData;
protected MyObjectOutputStream(int myData, OutputStream out) throws IOException, SecurityException {
super(out);
m_myData = myData;
write( m_myData );
super.writeStreamHeader();
}
protected void writeStreamHeader() throws IOException {
// work is done in the constructor
}
}
答案 3 :(得分:0)
使用合成而不是继承。
public class MyObjOutStream implements DataOutput, ObjectOutput, ObjectStreamConstants {
//same interfaces that ObjectOutputStream implements
private ObjectOutputStream objOutStream;
//implement all the methods below
}
只有在您准备好的情况下才会实例化ObjectOutputStream。您需要在接口中实现的其余方法只能在objOutStream