カスタムシリアライズ:writeObject と readObject
writeObject と readObject をオーバーライドし、暗号化、圧縮、カスタムフィールド処理を実装します。
「カスタムシリアライズ:writeObject と readObject」はCoddyKit上の無料Java Academyレッスンです。 これはレッスン3/4です。 下記で完全なレッスンを無料で読むことができます。その後、ブラウザ内の組み込みコードエディタと24時間対応の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()はデシリアライズ後に呼び出されます。置き換えるオブジェクトを返すことで、シングルトンやenumにおいてデシリアライズ後もインスタンスが1つだけ存在するようにできます。
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();
}Serialization Proxyパターン
堅牢な方法として、最小限の状態を保持するprivateなstatic内部クラスを作成し、writeReplaceでそのプロキシを書き込み、プロキシのreadResolveで元のオブジェクトを再構築します。
パフォーマンスに関する考慮事項
カスタムシリアライズではメソッド呼び出しのオーバーヘッドが発生しますが、ペイロードサイズを大幅に削減できる場合があります。最適化の前にベンチマークを実施し、最大限の制御が必要な場合はExternalizableを使用してください。
クイックチェック
writeObjectとreadObjectで、順序について何が成り立っていなければなりませんか。
まとめ
暗号化、圧縮、またはカスタム形式を扱うにはwriteObjectとreadObjectをオーバーライドします。シングルトンにはreadResolveを使用します。必ず、書き込んだ順序と同じ順序で読み取ってください。
よくある質問
「カスタムシリアライズ:writeObject と readObject」レッスンは無料ですか?
はい。「カスタムシリアライズ:writeObject と readObject」の完全なテキストはこのウェブで無料で読めます。インタラクティブに演習し(組み込みコードエディタと24時間対応のAIチューター)、Java Academyコースの残りをアンロックするには、CoddyKit PROにアップグレードしてください。 Java Academyコースには全4レッスンが含まれています。
「カスタムシリアライズ:writeObject と readObject」で何を学びますか?
writeObject と readObject をオーバーライドし、暗号化、圧縮、カスタムフィールド処理を実装します。 ブラウザで直接実行するハンズオンコードでJava Academyを演習し、24時間対応のAIチューターがレッスンを進める中での質問に答えます。
Java Academyを始めるのに経験は必要ですか?
事前経験は必要ありません。CoddyKitのJava Academyは初級者から上級者向けに構成されているため、ここから始めるか最初から始めて、自分のペースで進むことができます。 これはレッスン3/4です。
「カスタムシリアライズ:writeObject と readObject」レッスンにはどのくらい時間がかかりますか?
ほとんどのCoddyKitレッスンは約5~10分かかります。各レッスンはコンパクトでインタラクティブなので、着実に進歩し、ウェブとアプリ全体で正確に前回の場所から再開できます。
このJava Academyレッスンでコードを書いて実行できますか?
はい。すべてのJava Academyレッスンに組み込みコードエディタが含まれているため、ブラウザでリアルコードを書いて実行し、即座のAIフィードバックを取得できます。ローカル設定は不要です。
このコースのすべてのレッスン
- Java シリアライズの基本
- transient フィールドと serialVersionUID
- カスタムシリアライズ:writeObject と readObject
- 最新の代替手段:JSON と Protocol Buffers