如何重写ObjectOutputStream.writeStreamHeader()?
可以重写方法 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;
}
它不起作用,因为在初始化 m_myData
之前调用 super()
,并且 >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>();
}
这似乎可行,但是有更好的(不那么笨拙的)方法吗?
The method ObjectOutputStream.writeStreamHeader()
can be overridden to prepend or append data to the header. However, if that data is based on an argument passed to the derived class's constructor like:
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;
}
it doesn't work because super()
is called before m_myData
is initialized and super()
calls writeStreamHeader()
. The only way I can think to work around this is by using ThreadLocal
like:
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>();
}
This seems to work, but is there a better (less clunky) way?
如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。
绑定邮箱获取回复消息
由于您还没有绑定你的真实邮箱,如果其他用户或者作者回复了您的评论,将不能在第一时间通知您!
发布评论
评论(4)
使用组合而不是继承。
仅当您准备好时才实例化 ObjectOutputStream。 您需要在接口中实现的其余方法只需调用 objOutStream 上的相同方法即可
Use composition instead of inheritance.
Instance the ObjectOutputStream only when you are ready to do so. The remaining methods you need to implement in the interfaces can just call the same methods on
objOutStream
从构造函数中调用非最终方法通常是一个坏主意(正是出于您提出的原因)。
您可以在不扩展 ObjectOutputStream 的情况下实现自定义序列化吗? 我正在考虑流组合。 例如,您可以通过在 ObjectOutputStream 之前将标头写入底层 OutputStream 来添加标头。 这显然不能在 ObjectOutputStream 的子类中完成,但可以轻松地从外部完成。
如果您愿意,您可以将这一切很好地包装在 ObjectOutput 接口后面,正如 Stu Thompson 在他的回答中建议的那样,这样它看起来就像一个 ObjectOutputStream 一样。
更新:
查看 JavaDocs 和 ObjectOutputStream 的源代码,发现有第二个(受保护的)构造函数,它不会调用
writeStreamHeader()
。但是,该构造函数也不会初始化其他内部结构。 引用文档,
它的目的是“用于完全重新实现 ObjectOutputStream 的子类
不必分配仅由 ObjectOutputStream 的此实现使用的私有数据。在这种情况下,它还调用一些其他方法,例如“writeObjectOverride”。混乱...
It is generally a bad idea to call non-final methods from the constructor (for exactly the reason you presented).
Can you achieve your custom serialization without extending ObjectOutputStream? I am thinking about stream composition. For example, you could prepend your header by writing it to the underlying OutputStream before ObjectOutputStream does. This can obviously not be done in a subclass of ObjectOutputStream, but it can easily be done from the outside.
If you want, you can wrap this all up nicely behind the ObjectOutput interface as Stu Thompson suggested in his answer, so that it can look to the outside almost like an ObjectOutputStream.
Update:
Looking at the JavaDocs and source for ObjectOutputStream, there is a second (protected) constructor, that does not call
writeStreamHeader()
.However, this constructor also does not initialize other internal structures. To quote the docs,
it is intended "for subclasses that are completely reimplementing ObjectOutputStream
to not have to allocate private data just used by this implementation of ObjectOutputStream". In this case it also calls some other methods, such as "writeObjectOverride". Messy...
你就不能这样做吗? 当您初始化所需字段时,忽略超级构造函数中的 writeStreamHeader 调用并自己执行一个:
编辑:
或者,按照 Thilo,可以这样写:
Couldn't you do it like this. Ignore the writeStreamHeader call from the super constructor and do one yourself, when you have initialized the needed field:
EDIT:
Or, as suggested by Thilo, it could be written like:
有一个通用的方法可以解决此类问题。 创建类和内部类,并在外部作用域中引用变量。 (请注意,这仅适用于
-target 1.4
或 grter,这是当前版本的 javac 中的默认设置。使用-target 1.3
您将获得 NPE。)但是,在构造
ObjectOuputStream
之前将数据写出可能会更容易。There is a general way to solve this sort of problem. Make the class and inner class and reference a variable in the outer scope. (Note, this only works with
-target 1.4
or greter, which is the default in current versions of javac. With-target 1.3
you will get an NPE.)But, it's probably easier just to write the data out before constructing the
ObjectOuputStream
.