シリアル化は、オブジェクトをバイトストリームに変換し、保存または転送するためのメカニズムです。Javaでは、シリアル化は1.1バージョンでプラットフォームとともに導入され、分散アプリケーションの人気とそれらの間でのデータ交換の必要性に応じてAPIの一部として提供されました。この解決策は、JVM間で複雑なオブジェクトグラフを簡素に転送し、その状態を保存することを可能にし、開発者にとってプロセスを透過的にしました。
シリアル化の問題は、データの整合性を厳格に守り、クラスのバージョン管理を行い、複雑な構造(例えば、循環参照を持つグラフ)を正しく処理する必要があることです。すべてのオブジェクトがシリアル化可能ではなく(例えば、ストリーム、ソケット、OSリソースなど)、シリアル化はセキュリティに特別な注意を必要とします。
解決策は、Serializableインターフェースを使用して実装されます:
import java.io.*; class Person implements Serializable { private static final long serialVersionUID = 1L; private String name; private transient int age; // シリアル化されない public Person(String name, int age) { this.name = name; this.age = age; } }
ObjectOutputStreamとObjectInputStreamを使用することで、オブジェクトをファイルに書き込み、復元することができます:
Person p = new Person("Alice", 30); ObjectOutputStream oos = new ObjectOutputStream(new FileOutputStream("person.ser")); oos.writeObject(p); // シリアル化 ObjectInputStream ois = new ObjectInputStream(new FileInputStream("person.ser")); Person restored = (Person) ois.readObject();
主な特徴:
Serializableインターフェースを実装する必要があります。transient修飾子を持つフィールドはシリアル化されません。非シリアル化可能なフィールドを持つオブジェクトをシリアル化できますか、それが使用されていない場合でも?
回答: フィールドがtransientとしてマークされている場合、全くシリアル化されず、そのプロセスは例外をスローしません。フィールドがシリアル化不可能であり、transientでない場合、NotSerializableExceptionが発生します。
クラスがSerializableを実装していても、静的フィールドはシリアル化可能ですか?
回答: いいえ、静的フィールドはシリアル化されません。なぜなら、それらはクラスに属し、インスタンスには属さないからです。インスタンスの状態だけが保存されます。
シリアル化後にクラスの構造が変更された場合(例えば、フィールドを追加または削除した場合)どうなりますか?
回答: serialVersionUIDを指定していて、構造が互換性のない形で変更された場合、デシリアライズ時にInvalidClassExceptionが発生します。互換性を確保するために、シリアライザのヒントやserialVersionUIDの手動管理が使用されます。
serialVersionUIDを未宣言とし、クラスの互換性のないバージョンによるエラーを受けること。transient修飾子を無視することが、機密データの漏洩につながる可能性がある。エンジニアたちはserialVersionUIDを追加せず、OSリソースを参照するフィールドをtransientとして宣言せずにオブジェクトをシリアル化することに決定しました。アプリケーションとクラスを更新した後、InvalidClassExceptionが発生し、オブジェクトの整合性が失われ、デシリアライズが機能しなくなりました。
利点:
欠点:
シリアル化のために、明示的なserialVersionUIDを持つ移植性のあるクラスが実装され、すべてのリソースフィールドがtransientとして宣言され、手動シリアル化が重要なポイントを制御します。
利点:
欠点: