私が持っています:
class MyClass extends MyClass2 implements Serializable {
//...
}
MyClass2には、シリアル化できないプロパティがあります。このオブジェクトをシリアル化(および逆シリアル化)するにはどうすればよいですか?
訂正:もちろん、MyClass2はインターフェイスではなくクラスです。
他の誰かが指摘したように、Josh Blochの11章 Effective Java は、Java Serialization。
あなたの質問に関連するその章からのいくつかのポイント:
これを説明する簡単な例を以下に示しました。
class MyClass extends MyClass2 implements Serializable{
public MyClass(int quantity) {
setNonSerializableProperty(new NonSerializableClass(quantity));
}
private void writeObject(Java.io.ObjectOutputStream out)
throws IOException{
// note, here we don't need out.defaultWriteObject(); because
// MyClass has no other state to serialize
out.writeInt(super.getNonSerializableProperty().getQuantity());
}
private void readObject(Java.io.ObjectInputStream in)
throws IOException {
// note, here we don't need in.defaultReadObject();
// because MyClass has no other state to deserialize
super.setNonSerializableProperty(new NonSerializableClass(in.readInt()));
}
}
/* this class must have no-arg constructor accessible to MyClass */
class MyClass2 {
/* this property must be gettable/settable by MyClass. It cannot be final, therefore. */
private NonSerializableClass nonSerializableProperty;
public void setNonSerializableProperty(NonSerializableClass nonSerializableProperty) {
this.nonSerializableProperty = nonSerializableProperty;
}
public NonSerializableClass getNonSerializableProperty() {
return nonSerializableProperty;
}
}
class NonSerializableClass{
private final int quantity;
public NonSerializableClass(int quantity){
this.quantity = quantity;
}
public int getQuantity() {
return quantity;
}
}
MyClass2は単なるインターフェイスであるため、技術的にはプロパティがなく、メソッドのみがあります。それ自体をシリアル化できないインスタンス変数がある場合、それを回避する唯一の方法は、それらのフィールドを一時的に宣言することです。
例:
private transient Foo foo;
フィールドトランジェントを宣言すると、シリアル化および逆シリアル化プロセス中に無視されます。一時フィールドを持つオブジェクトをデシリアライズすると、そのフィールドの値は常にデフォルト(通常はnull)になることに注意してください。
他のシステム状態に基づいて一時フィールドを初期化するために、クラスのreadResolve()メソッドをオーバーライドすることもできます。
可能であれば、シリアル化できない部分を一時的に設定できます
private transient SomeClass myClz;
それ以外の場合は、 Kryo を使用できます。 Kryoは、Javaの高速かつ効率的なオブジェクトグラフシリアル化フレームワークです(例Java Java.awt.Colorのシリアル化には170バイト、Kryoのみ4バイトが必要)、また、Kryoはobject->bytes->object
ではなく、オブジェクトからオブジェクトへの直接コピーである、ディープおよびシャローの自動コピー/クローン作成を実行できます。
Kryoの使用方法の例を次に示します
Kryo kryo = new Kryo();
// #### Store to disk...
Output output = new Output(new FileOutputStream("file.bin"));
SomeClass someObject = ...
kryo.writeObject(output, someObject);
output.close();
// ### Restore from disk...
Input input = new Input(new FileInputStream("file.bin"));
SomeClass someObject = kryo.readObject(input, SomeClass.class);
input.close();
シリアライズされたオブジェクトは、正確なシリアライザーを登録することでも圧縮できます。
kryo.register(SomeObject.class, new DeflateCompressor(new FieldSerializer(kryo, SomeObject.class)));
MyClass2を変更できる場合、これに対処する最も簡単な方法は、プロパティtransientを宣言することです。
writeObject()
とreadObject()
を実装し、それらのフィールドを手動でシリアル化/逆シリアル化する必要があります。詳細については、Java.io.Serializable
のjavadocページを参照してください。 Josh BlochのEffective Javaには、堅牢で安全なシリアル化の実装に関する優れた章もあります。
MyClass2のそのメンバーがシリアル化できない理由に依存します。
MyClass2をシリアル化された形式で表現できない正当な理由がある場合、サブクラスであるため、同じ理由がMyClassに適用される可能性が高くなります。
ReadObjectとwriteObjectを実装することにより、MyClassのカスタムシリアル化フォームを作成して、シリアル化されたデータからMyClassのMyClass2インスタンスデータの状態を適切に再作成できるようにすることが可能です。これは、MyClass2のAPIが修正され、Serializableを追加できない場合の方法です。
しかし、最初にMyClass2がシリアル化できない理由を理解し、おそらく変更する必要があります。
transientキーワードを調べることから開始できます。これは、オブジェクトの永続状態の一部ではないフィールドとしてマークします。
いくつかの可能性が現れ、私はそれらをここで再開します:
XStream は、高速化するための優れたライブラリですJava Serializableであるかどうかに関係なく、任意のオブジェクトのXMLシリアル化に。XMLターゲット形式が適合しない場合でもあなたは、ソースコードを使用してそれを行う方法を学ぶことができます。
シリアル化できないクラス(または少なくともサブクラス)のインスタンスをシリアル化する便利なアプローチは、シリアルプロキシと呼ばれます。基本的に、writeReplaceを実装して、元のオブジェクトのコピーを返すreadResolveを実装する完全に異なるシリアル化可能クラスのインスタンスを返します。 Usenet でJava.awt.BasicStrokeをシリアル化する例を書いた