El método ObjectOutputStream.writeStreamHeader()
se puede anular para anteponer o anexar datos al encabezado. Sin embargo, si esos datos se basa en un argumento pasado al constructor de la clase derivada como:Cómo anular 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;
}
que no funciona porque super()
se llama antes de m_myData
se inicializa y super()
llamadas writeStreamHeader()
. La única manera que puedo pensar para evitar esto es mediante el uso de ThreadLocal
como:
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>();
}
Esto parece funcionar, pero hay una manera mejor (menos torpe)?
Me gusta esta solución porque anula writeStreamHeader() "como estaba previsto" y el encabezado se escribe en el "momento correcto" y no hace suposiciones sobre cuándo el constructor de la clase base llama al método. Como tal, es "a prueba de futuro". –
aseado. Aparentemente, el alcance externo se inicializa antes que el constructor de la superclase. – Thilo
Sí, la especificación de VM tuvo que cambiarse para permitir ese tipo de cosas. Todavía puede complicarse, la última vez que verifiqué que un ejemplo en el JLS no funcionaba con el javac de la época. –