如何重写ObjectOutputStream.writeStreamHeader()?
-
23-08-2019 - |
题
方法 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>();
}
这似乎可行,但是有更好(不那么笨重)的方法吗?
解决方案
有是解决这种问题的一般方法。使类和内部类和在外部范围内引用的变量。 (注意,这仅适用于-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
de之前。
其他提示
你不能像这样做。从超级构造函数忽略writeStreamHeader呼叫,做一个自己,当你已经初始化所需要的领域:
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();
}
}
修改强>
或者,通过蒂洛的建议,它可以写成如下:
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
}
}
从构造函数中调用非最终方法通常是一个坏主意(正是出于您提出的原因)。
您可以在不扩展 ObjectOutputStream 的情况下实现自定义序列化吗?我正在考虑流组合。例如,您可以通过在 ObjectOutputStream 之前将标头写入底层 OutputStream 来添加标头。这显然不能在 ObjectOutputStream 的子类中完成,但可以轻松地从外部完成。
out.write(myExtraHeader);
ObjectOutputStream oos = new ObjectOutputStream(out);
如果您愿意,您可以将这一切很好地包装在 ObjectOutput 接口后面,正如 Stu Thompson 在他的回答中建议的那样,这样它看起来就像一个 ObjectOutputStream 一样。
更新:
查看 JavaDocs 和 ObjectOutputStream 的源代码,有第二个(受保护的)构造函数,它不调用 writeStreamHeader()
.
但是,该构造函数也不会初始化其他内部结构。为了引用文档,它旨在“针对完全重新进化ObjectOutputStream的子类,以不必分配仅由ObjectOutputStream的实现使用的私有数据”。在这种情况下,它还调用一些其他方法,例如“writeObjectOverride”。凌乱的...
使用组合物,而不是继承。
public class MyObjOutStream implements DataOutput, ObjectOutput, ObjectStreamConstants {
//same interfaces that ObjectOutputStream implements
private ObjectOutputStream objOutStream;
//implement all the methods below
}
实例用ObjectOutputStream只有当你准备好这样做。你需要其余的方法在接口来实现只需致电objOutStream
同样的方法