0Pricing
Java Academy · 강의

사용자 정의 직렬화: writeObject와 readObject

암호화, 압축 또는 사용자 정의 필드 처리를 위해 writeObject와 readObject를 재정의합니다.

사용자 정의 직렬화: writeObject와 readObject은(는) CoddyKit의 무료 Java Academy 강의입니다. 이것은 4개 중 3번째 강의입니다. 아래에서 전체 강의를 무료로 읽을 수 있으며, 내장 코드 에디터와 24/7 AI 튜터와 함께 브라우저에서 직접 실습할 수 있습니다. 이 강의는 Java Academy 학습 경로의 일부이며, 진행 상황이 웹과 CoddyKit 앱에 동기화됩니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

기본 직렬화만으로 충분하지 않을 때

기본 직렬화는 transient가 아닌 모든 필드를 있는 그대로 저장합니다. 암호화, 압축 또는 다른 표현이 필요한 경우도 있습니다. 이때 writeObject / readObject 후크를 사용합니다.

writeObject 선언

private void writeObject(ObjectOutputStream oos) 메서드를 추가하십시오. Java는 기본 방식 대신 이 메서드를 호출합니다. 무엇을 기록할지 정확하게 제어할 수 있습니다.

private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.defaultWriteObject(); // write non-transient fields normally
    oos.writeUTF(encrypt(this.secret)); // write encrypted secret
}

readObject 선언

private void readObject(ObjectInputStream ois) 메서드를 추가하십시오. Java는 역직렬화 중에 이 메서드를 호출합니다. 기록한 순서와 정확히 같은 순서로 읽어야 합니다.

private void readObject(ObjectInputStream ois)
        throws IOException, ClassNotFoundException {
    ois.defaultReadObject(); // restore non-transient fields
    this.secret = decrypt(ois.readUTF()); // decrypt and restore
}

순서가 중요합니다

writeObject에서 기록하는 내용은 readObject에서 반드시 같은 순서로 다시 읽어야 합니다. 순서가 일치하지 않으면 StreamCorruptedException이 발생합니다.

private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.writeInt(version);
    oos.writeUTF(data);
}
private void readObject(ObjectInputStream ois)
        throws IOException, ClassNotFoundException {
    this.version = ois.readInt();  // same order
    this.data    = ois.readUTF();
}

직렬화 중 데이터 압축

writeObject 내부에서 스트림을 GZIPOutputStream으로 감싸 큰 필드를 압축한 다음, readObject 내부에서 GZIPInputStream으로 압축을 해제하십시오.

private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.defaultWriteObject();
    ByteArrayOutputStream bos = new ByteArrayOutputStream();
    try (GZIPOutputStream gz = new GZIPOutputStream(bos)) {
        gz.write(largePayload.getBytes());
    }
    oos.writeObject(bos.toByteArray());
}

readResolve 후크

readResolve()는 역직렬화 후에 호출됩니다. 대체 객체를 반환할 수 있으므로, 역직렬화 후에도 인스턴스가 하나만 존재하도록 보장해야 하는 싱글턴과 열거형에 유용합니다.

public class AppConfig implements Serializable {
    private static final AppConfig INSTANCE = new AppConfig();
    private AppConfig() {}
    public static AppConfig getInstance() { return INSTANCE; }
    private Object readResolve() { return INSTANCE; } // return singleton
}

writeReplace 후크

writeReplace()는 직렬화 전에 호출됩니다. 대신 직렬화할 다른 객체를 반환할 수 있으므로, 프록시 패턴과 직렬화 대체 객체에 유용합니다.

private Object writeReplace() {
    return new UserProxy(this.id); // serialize a lightweight proxy
}

readObject에서 필드 검증

readObject 내부에 검증 로직을 추가하여 심층 방어 전략의 일부로 잘못되었거나 변조된 데이터를 거부할 수 있습니다.

private void readObject(ObjectInputStream ois)
        throws IOException, ClassNotFoundException {
    ois.defaultReadObject();
    if (age < 0 || age > 150) {
        throw new InvalidObjectException("Invalid age: " + age);
    }
}

버전 변경 처리

writeObject에서 버전 필드를 사용하면 마이그레이션 중에 readObject가 이전 형식과 새 형식을 모두 원활하게 처리할 수 있습니다.

private static final int SERIAL_VERSION = 2;
private void writeObject(ObjectOutputStream oos) throws IOException {
    oos.defaultWriteObject();
    oos.writeInt(SERIAL_VERSION);
    if (SERIAL_VERSION >= 2) oos.writeUTF(email); // new field
}
private void readObject(ObjectInputStream ois)
        throws IOException, ClassNotFoundException {
    ois.defaultReadObject();
    int v = ois.readInt();
    if (v >= 2) this.email = ois.readUTF();
}

직렬화 프록시 패턴

견고한 접근 방식은 최소한의 상태를 저장하는 비공개 정적 내부 클래스를 작성한 다음, writeReplace로 프록시를 기록하고 프록시의 readResolve로 원래 객체를 재구성하는 것입니다.

성능 고려 사항

사용자 지정 직렬화는 메서드 호출 오버헤드를 추가하지만 페이로드 크기를 크게 줄일 수 있습니다. 최적화하기 전에 성능을 측정하고, 최대한의 제어가 필요하면 외부 직렬화 방식을 사용하십시오.

빠른 확인

writeObject와 readObject의 순서에 대해 무엇이 참이어야 합니까?

복습

암호화, 압축 또는 사용자 지정 형식을 사용하려면 writeObject / readObject를 재정의하십시오. 싱글턴에는 readResolve를 사용하십시오. 항상 기록한 순서와 같은 순서로 읽으십시오.

자주 묻는 질문

“사용자 정의 직렬화: writeObject와 readObject” 강의는 무료인가요?

네 — “사용자 정의 직렬화: writeObject와 readObject” 전체 내용을 이 웹사이트에서 무료로 읽을 수 있습니다. 인터랙티브하게 실습하려면(내장 코드 에디터와 24/7 AI 튜터), CoddyKit PRO로 업그레이드하면 Java Academy 강의 전체를 잠금 해제할 수 있습니다. Java Academy 강의에는 총 4개의 강의가 포함되어 있습니다.

“사용자 정의 직렬화: writeObject와 readObject”에서 뭘 배우나요?

암호화, 압축 또는 사용자 정의 필드 처리를 위해 writeObject와 readObject를 재정의합니다. 브라우저에서 직접 실행하는 실습 코드로 Java Academy을(를) 배우며, 24/7 AI 튜터가 강의를 진행하면서 질문에 답변해줍니다.

Java Academy을(를) 시작하는 데 경험이 필요한가요?

사전 경험은 필요하지 않습니다. CoddyKit의 Java Academy은(는) 초급자부터 고급 학습자까지를 위해 구성되어 있으므로, 여기서 시작하거나 처음부터 시작할 수 있으며 자신의 속도대로 진행할 수 있습니다. 이것은 4개 중 3번째 강의입니다.

“사용자 정의 직렬화: writeObject와 readObject” 강의는 얼마나 걸리나요?

대부분의 CoddyKit 강의는 약 5~10분이 소요됩니다. 각 강의는 간결하고 인터랙티브하여 꾸준한 진행이 가능하며, 웹과 앱에서 중단한 부분부터 바로 시작할 수 있습니다.

이 Java Academy 강의에서 코드를 작성하고 실행할 수 있나요?

네. 모든 Java Academy 강의에는 내장 코드 에디터가 포함되어 있으므로, 브라우저에서 바로 실제 코드를 작성하고 실행한 후 즉시 AI 피드백을 받을 수 있습니다 — 로컬 설정이 필요 없습니다.

이 강의의 모든 강의

  1. Java 직렬화 기초
  2. transient 필드와 serialVersionUID
  3. 사용자 정의 직렬화: writeObject와 readObject
  4. 최신 대안: JSON과 Protocol Buffers
← Java Academy(으)로 돌아가기