方法 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();
        }
    };
}

但是,它可能更容易只是将数据写入了构建ObjectOuputStreamde之前。

其他提示

你不能像这样做。从超级构造函数忽略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同样的方法

许可以下: CC-BY-SA归因
不隶属于 StackOverflow
scroll top