ObjectOutputStream.writestreamHeader ()를 무시하는 방법?
-
23-08-2019 - |
문제
방법 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
또는 현재 버전의 Javac의 기본값 인 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
.
다른 팁
이렇게 할 수 없었습니다. 필요한 필드를 초기화 한 경우 슈퍼 생성자의 WritesTreamEader 호출을 무시하고 직접 수행하십시오.
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
}
}
일반적으로 생성자로부터 비 결절 방법을 호출하는 것은 나쁜 생각입니다 (정확히 당신이 제시 한 이유).
ObjectOutputStream을 확장하지 않고 사용자 정의 직렬화를 달성 할 수 있습니까? 스트림 구성에 대해 생각하고 있습니다. 예를 들어, ObjectOutputStream 이전에 기본 출력 스트림에 헤더를 작성하여 헤더를 선불로 작성할 수 있습니다. 이것은 분명히 ObjectOutputStream의 서브 클래스에서 수행 할 수 없지만 외부에서 쉽게 수행 할 수 있습니다.
out.write(myExtraHeader);
ObjectOutputStream oos = new ObjectOutputStream(out);
원한다면 Stu Thompson이 그의 대답에서 제안한 것처럼 ObjectOutput 인터페이스 뒤에이 모든 것을 멋지게 감싸서 외부를 거의 ObjectOutputStream처럼 볼 수 있습니다.
업데이트:
ObjectOutputStream의 javadocs 및 소스를 보면 호출하지 않는 두 번째 (보호 된) 생성자가 있습니다. writeStreamHeader()
.
그러나이 생성자는 다른 내부 구조를 초기화하지 않습니다. 문서를 인용하기 위해, "대상의 PutputStream의 구현에 사용 된 개인 데이터를 할당 할 필요가 없도록 ObjectOutputStream을 완전히 상환하는 서브 클래스의 경우"입니다. 이 경우 "writeObjectOverRide"와 같은 다른 방법도 호출됩니다. 지저분한...
상속 대신 구성을 사용하십시오.
public class MyObjOutStream implements DataOutput, ObjectOutput, ObjectStreamConstants {
//same interfaces that ObjectOutputStream implements
private ObjectOutputStream objOutStream;
//implement all the methods below
}
대상이 될 때만 ObjectOutputStream 인스턴스. 인터페이스에서 구현 해야하는 나머지 방법은 동일한 메소드를 호출 할 수 있습니다. objOutStream