23

私はEffectiveJavaのシリアル化の章を読んでいます。私は本にある以下の段落を理解しようとしています。

シリアル化および拡張可能なインスタンスフィールドを持つクラスを実装する場合は、注意が必要です。インスタンスフィールドがデフォルト値(整数型の場合はゼロ、ブール型の場合はfalse、オブジェクト参照型の場合はnull)に初期化された場合に違反する不変条件がクラスにある場合は、次のreadObjectNoDataメソッドをクラスに追加する必要があります。

// readObjectNoData for stateful extendable serializable classes
private void readObjectNoData() throws InvalidObjectException {
    throw new InvalidObjectException("Stream data required");
}

その声明が何を意味するのかわかりません。

これをテストするために、 Person(シリアル化可能と拡張可能の両方)というクラスを作成しました

class Person implements Serializable {

    private String name;
    private int age;

    Person() {
        this("default", 1);
    }
    
    Person(String name, int age) {
        this.name = name;
        this.age = age;
    }
}

–およびクラス:それを拡張するEmployee 。

class Employee extends Person {

    String address;

    public Employee() {
        super();
        address = "default_address";
    }

    public Employee(String name, int age, String address) {
        super(name, age);
        this.address = address;
    }
}

私が作成したPersonクラスに不変条件はありますか?いつ違反されますか?EmployeeクラスのreadObjectData()メソッドのコードをコピーして貼り付けましたが、呼び出されませんでした。メソッドはいつ呼び出されますか?私は何かが足りないのですか?readObject()

4

4 に答える 4

22

Java Object Serialization SpecificationのreadObjectNoDataセクションは興味深いようです(以下を参照)。

質問への編集は完璧な例を示しています。延長されなかった場合、および後で延長Employeeされた場合、パーツは空の文字列と0エージに初期化されます。このメソッドを使用して、それらをそれぞれ「名前」と1に初期化できます。serializedPersondeserializedPerson

シリアル化可能なオブジェクトの場合、readObjectNoDataメソッドを使用すると、サブクラスインスタンスが逆シリアル化され、シリアル化ストリームが問題のクラスを逆シリアル化されたオブジェクトのスーパークラスとしてリストしない場合に、クラスが自身のフィールドの初期化を制御できます。これは、受信側が送信側とは異なるバージョンの逆シリアル化されたインスタンスのクラスを使用し、受信側のバージョンが送信側のバージョンによって拡張されていないクラスを拡張する場合に発生する可能性があります。これは、シリアル化ストリームが改ざんされている場合にも発生する可能性があります。したがって、readObjectNoDataは、「敵対的」または不完全なソースストリームにもかかわらず、逆シリアル化されたオブジェクトを適切に初期化するのに役立ちます。

private void readObjectNoData() throws ObjectStreamException;

シリアル化可能な各クラスは、独自のreadObjectNoDataメソッドを定義できます。シリアライズ可能なクラスがreadObjectNoDataメソッドを定義していない場合、上記の状況では、クラスのフィールドはデフォルト値に初期化されます(JavaTM言語仕様、第2版のセクション4.5.5にリストされています)。この動作は、readObjectNoDataメソッドのサポートが導入されたときのJavaTM 2 SDK、StandardEditionのバージョン1.4より前のObjectInputStreamの動作と一致しています。シリアライズ可能なクラスがreadObjectNoDataメソッドを定義し、前述の条件が発生した場合、

于 2011-09-16T13:29:02.553 に答える
3

私が作成したPersonクラスに不変条件はありますか?いつ違反されますか?

name明示的にはありませんが、クラス内の他のメソッドは、それが決してないことを想定しており、もしあったとしてもnullスローすることを想像してくださいNullPointerException。この場合、の非ヌルname性は不変です。

クラスのreadObjectData()メソッドのコードをコピーしましたが、呼び出されませんでした。EmployeeメソッドはいつreadObject()呼び出されますか?

readObjectData()シリアル化に関連する方法はありません。これはタイプミスである必要があります。このreadObject()メソッドは、シリアル化されたオブジェクトが逆シリアル化されるたびに呼び出されます。

メソッドを含むクラスのサブクラスを逆シリアル化するときに、readObjectNoData()メソッドはいくつかのあいまいなコーナーケースでヒットします。

Sun Oracle Webサイトの高度なシリアル化の記事では、これらのシリアル化ヘルパーメソッドの目的について説明しています。そこから始めて、遭遇する可能性のある後続の質問を投稿することをお勧めします。

(アップデート)

気になる方のために、readObjectNoDataメソッドがリリース1.4で追加され、既存のシリアライズ可能なクラスへのシリアライズ可能なスーパークラスの追加を含むコーナーケースをカバーしています。詳細については、シリアル化仕様のシリアル化、3.5を参照してください。

参照されるテキストは次のとおりです。

シリアル化可能なオブジェクトの場合、readObjectNoDataメソッドを使用すると、サブクラスインスタンスが逆シリアル化され、シリアル化ストリームが問題のクラスを逆シリアル化されたオブジェクトのスーパークラスとしてリストしない場合に、クラスが自身のフィールドの初期化を制御できます。これは、受信側が送信側とは異なるバージョンの逆シリアル化されたインスタンスのクラスを使用し、受信側のバージョンが送信側のバージョンによって拡張されていないクラスを拡張する場合に発生する可能性があります。これは、シリアル化ストリームが改ざんされている場合にも発生する可能性があります。したがって、readObjectNoDataは、「敵対的」または不完全なソースストリームにもかかわらず、逆シリアル化されたオブジェクトを適切に初期化するのに役立ちます。

したがって、これは2つの場合に発生する可能性があります。

  • オブジェクトストリームをデコードするJVMには、逆シリアル化されるサブクラスの新しいバージョン(Employee)があり、親クラスを拡張するもの(Person)があります。オブジェクトストリームを最初に*エンコード*したJVMには、これらのクラスの異なる古いバージョンがありますPersonが、まだスーパークラスではありませんでしたEmployee
  • 誰かが物事を壊すために意図的にオブジェクトストリームをいじりました。
于 2011-09-16T13:25:27.517 に答える
3

「拡張可能」とは、「サブクラスを持つことができる」という意味です。

readObjectNoDataは、シリアライザー(ライター)が基本クラスのないバージョンのクラスを処理しているのに対し、クラスのデシリアライザー(リーダー)がサブクラスに基づくクラスのバージョンを持っているという珍しい場合に使用されます。サブクラスは、readObjectNoDataを実装することで、「基本クラスがシリアル化されたデータに含まれていなくても問題ありません。空のクラスを作成するだけです」と言うことができます。これらのリリースノートを参照してください。

于 2011-09-16T13:32:30.630 に答える
0

Personクラスの不変条件は、次のようになります。

age must be greater than 0

したがって、Personクラスがデフォルト値0(http://download.oracle.com/javase/tutorial/java/nutsandbolts/datatypes.htmlを参照)でインスタンス化されると、その不変条件に違反することになります。

ただし、デフォルトのコンストラクターがあれば問題ありません:)

于 2011-09-16T13:24:32.627 に答える