2009-07-06 46 views
5

可以重写方法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()电话writeStreamHeader()super()被调用。我能想到的唯一的办法来解决,这是通过使用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>(); 
} 

这似乎是工作,但有一个更好的(不太笨重)的方式?

回答

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

0

用的组合物,而不是继承。

public class MyObjOutStream implements DataOutput, ObjectOutput, ObjectStreamConstants { 
    //same interfaces that ObjectOutputStream implements 

    private ObjectOutputStream objOutStream; 

    //implement all the methods below 
} 

仅当您准备好时才会对ObjectOutputStream实例进行操作。你需要其余的方法在接口来实现可以叫上objOutStream

+0

这比使用ThreadLocal更笨拙 – dfa 2009-07-06 07:46:02

+0

这是如何笨重?构图非常优雅。唯一的问题是所有的样板代码(方法体),因为Java缺乏代表的好语法。但是Eclipse可以自动生成它们。 – Thilo 2009-07-06 07:48:34

+2

@Thilo,我宁愿你的解决方案使用流组合 – dfa 2009-07-06 07:51:41

1

同样的方法它通常是一个坏主意来调用构造函数非最终方法(正是你所提出的理由)。

你可以实现你的自定义序列不延长的ObjectOutputStream?我正在考虑流组合。例如,您可以在ObjectOutputStream执行之前将其写入底层的OutputStream,从而预先添加您的头文件。这显然不能在ObjectOutputStream的子类中完成,但可以很容易地从外部完成。

out.write(myExtraHeader); 
    ObjectOutputStream oos = new ObjectOutputStream(out); 

如果你愿意,你可以很好地包裹这一切起来的ObjectOutput接口后面的斯图·汤普森在他的回答表明,以便它可以看看外面几乎像一个ObjectOutputStream。

更新:

望着的JavaDoc和源ObjectOutputStream的,还有一个第二(保护)的构造,这不叫writeStreamHeader()

然而,此构造也不会初始化其他内部结构。引用文档 它旨在“用于完全重新实现ObjectOutputStream 的子类不必分配此ObjectOutputStream的此实现使用的私有数据”。在这种情况下,它还会调用其他一些方法,例如“writeObjectOverride”。凌乱...

1

你不能像这样做。从超级构造函数忽略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(); 
} 
} 

编辑:

或者,通过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 
    } 
}