2009-07-06 67 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 
    } 
}