web-dev-qa-db-ja.com

Javaシリアル化できない部分を使用したシリアル化

私が持っています:

class MyClass extends MyClass2 implements Serializable {
  //...
}

MyClass2には、シリアル化できないプロパティがあります。このオブジェクトをシリアル化(および逆シリアル化)するにはどうすればよいですか?

訂正:もちろん、MyClass2はインターフェイスではなくクラスです。

52
Burkhard

他の誰かが指摘したように、Josh Blochの11章 Effective Java は、Java Serialization。

あなたの質問に関連するその章からのいくつかのポイント:

  • myClass2の非シリアル化可能フィールドの状態をシリアル化する場合、そのフィールドは直接またはゲッターとセッターを介してMyClassにアクセスできる必要があります。 MyClassは、readObjectメソッドとwriteObjectメソッドを提供することにより、カスタムシリアル化を実装する必要があります。
  • 非シリアル化可能フィールドのクラスには、(オブジェクトストリームへの書き込み用に)状態を取得し、(オブジェクトストリームからの読み取り時に)その状態で新しいインスタンスをインスタンス化できるAPIが必要です。
  • effective JavaのItem 74に従い、MyClass2mustはMyClassにアクセス可能な引数なしのコンストラクターを持っています。

これを説明する簡単な例を以下に示しました。


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;
  }
}
49
Scott Bale

MyClass2は単なるインターフェイスであるため、技術的にはプロパティがなく、メソッドのみがあります。それ自体をシリアル化できないインスタンス変数がある場合、それを回避する唯一の方法は、それらのフィールドを一時的に宣言することです。

例:

private transient Foo foo;

フィールドトランジェントを宣言すると、シリアル化および逆シリアル化プロセス中に無視されます。一時フィールドを持つオブジェクトをデシリアライズすると、そのフィールドの値は常にデフォルト(通常はnull)になることに注意してください。

他のシステム状態に基づいて一時フィールドを初期化するために、クラスのreadResolve()メソッドをオーバーライドすることもできます。

35
Mike Deck

可能であれば、シリアル化できない部分を一時的に設定できます

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)));
15
Radim Burget

MyClass2を変更できる場合、これに対処する最も簡単な方法は、プロパティtransientを宣言することです。

11
ykaganovich

writeObject()readObject()を実装し、それらのフィールドを手動でシリアル化/逆シリアル化する必要があります。詳細については、Java.io.Serializableのjavadocページを参照してください。 Josh BlochのEffective Javaには、堅牢で安全なシリアル化の実装に関する優れた章もあります。

6
sk.

MyClass2のそのメンバーがシリアル化できない理由に依存します。

MyClass2をシリアル化された形式で表現できない正当な理由がある場合、サブクラスであるため、同じ理由がMyClassに適用される可能性が高くなります。

ReadObjectとwriteObjectを実装することにより、MyClassのカスタムシリアル化フォームを作成して、シリアル化されたデータからMyClassのMyClass2インスタンスデータの状態を適切に再作成できるようにすることが可能です。これは、MyClass2のAPIが修正され、Serializableを追加できない場合の方法です。

しかし、最初にMyClass2がシリアル化できない理由を理解し、おそらく変更する必要があります。

5
Steve Jessop

transientキーワードを調べることから開始できます。これは、オブジェクトの永続状態の一部ではないフィールドとしてマークします。

4
Hank

いくつかの可能性が現れ、私はそれらをここで再開します:

  • WriteObject()およびreadObject()を sk として実装します
  • プロパティを一時的に宣言すると、 hank で最初に述べたようにシリアル化されません
  • boris-terzic で述べられているようにXStreamを使用する
  • tom-hawtin-tackline で指定されているシリアルプロキシを使用する
4
Burkhard

XStream は、高速化するための優れたライブラリですJava Serializableであるかどうかに関係なく、任意のオブジェクトのXMLシリアル化に。XMLターゲット形式が適合しない場合でもあなたは、ソースコードを使用してそれを行う方法を学ぶことができます。

3
Boris Terzic

シリアル化できないクラス(または少なくともサブクラス)のインスタンスをシリアル化する便利なアプローチは、シリアルプロキシと呼ばれます。基本的に、writeReplaceを実装して、元のオブジェクトのコピーを返すreadResolveを実装する完全に異なるシリアル化可能クラスのインスタンスを返します。 Usenet でJava.awt.BasicStrokeをシリアル化する例を書いた