私は持っている:
class MyClass extends MyClass2 implements Serializable {
//...
}
In MyClass2 は、シリアライズできないプロパティです。このオブジェクトをシリアライズ (およびデシリアライズ) するにはどうすればよいですか?
訂正: もちろん、MyClass2 はインターフェイスではなくクラスです。
私は持っている:
class MyClass extends MyClass2 implements Serializable {
//...
}
In MyClass2 は、シリアライズできないプロパティです。このオブジェクトをシリアライズ (およびデシリアライズ) するにはどうすればよいですか?
訂正: もちろん、MyClass2 はインターフェイスではなくクラスです。
他の誰かが指摘したように、Josh Bloch の「Effective Java 」の第 11 章は、Java シリアライゼーションに関する不可欠なリソースです。
あなたの質問に関連するその章からのいくつかのポイント:
これを説明する簡単な例を以下に書きました。
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.awt.Color の Java シリアル化には 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 プロパティを宣言することです。
MyClass2 のそのメンバーがシリアル化できない理由によって異なります。
MyClass2 をシリアル化された形式で表現できない正当な理由がある場合、サブクラスであるため、同じ理由が MyClass にも当てはまる可能性が高くなります。
MyClass の MyClass2 インスタンス データの状態をシリアル化されたデータから適切に再作成できるように、readObject と writeObject を実装することにより、MyClass のカスタム シリアル化されたフォームを作成できる場合があります。これは、MyClass2 の API が修正され、Serializable を追加できない場合の方法です。
しかし、最初に MyClass2 がシリアライズ可能でない理由を理解し、変更する必要があります。
writeObject()これらのフィールドのシリアル化/逆シリアル化を実装しreadObject()、手動で行う必要があります。詳細については、javadoc ページを参照しjava.io.Serializableてください。Josh Bloch の「Effective Java 」にも、堅牢で安全なシリアル化の実装に関する優れた章がいくつかあります。
いくつかの可能性が浮かび上がり、ここでそれらを再開します。
オブジェクトの永続状態の一部ではないフィールドをマークする、 transientキーワードを調べることから始めることができます。
XStreamは、シリアライズ可能かどうかに関係なく、任意のオブジェクトに対して Java から XML へのシリアライズを高速に行うための優れたライブラリです。XML ターゲット形式が自分に合わない場合でも、ソース コードを使用してその方法を学習できます。
シリアル化できないクラス(または少なくとものサブクラス)のインスタンスをシリアル化するための便利なアプローチは、シリアルプロキシとして知られています。基本的に、writeReplaceを実装して、元のオブジェクトのコピーを返すreadResolveを実装する完全に異なるシリアル化可能なクラスのインスタンスを返します。Usenetでjava.awt.BasicStrokeをシリアル化する例を書きました