ObjectOutputStream.writeStreamHeader() をオーバーライドするにはどうすればよいですか?

StackOverflow https://stackoverflow.com/questions/1085812

質問

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

これは機能するようですが、もっと良い(あまり不格好ではない)方法はありますか?

役に立ちましたか?

解決

この種の問題を解決する一般的な方法があります。クラスや内部クラスを作成し、外側のスコープで変数を参照。 (これが唯一のjavacの現在のバージョンではデフォルトである、-target 1.4またはgreterで動作し、注意してください。-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を構築する前にデータを書き出すために、おそらく簡単です。

他のヒント

こんなことはできなかったのか。スーパー コンストラクターからの 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
    }
}

一般に、コンストラクターから非finalメソッドを呼び出すことは悪い考えです(まさにあなたが提示した理由により)。

ObjectOutputStream を拡張せずにカスタム シリアル化を実現できますか?ストリーム構成を考えています。たとえば、ObjectOutputStream が実行する前にヘッダーを基になる OutputStream に書き込むことで、ヘッダーを先頭に追加できます。これは明らかに ObjectOutputStream のサブクラス内では実行できませんが、外部から簡単に実行できます。

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

必要に応じて、Stu Thompson が回答で示唆したように、これを ObjectOutput インターフェイスの背後でうまくまとめて、外側からは ObjectOutputStream のように見えるようにすることができます。

アップデート:

JavaDocs と ObjectOutputStream のソースを見ると、呼び出しを行わない 2 番目の (保護された) コンストラクターがあります。 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