39

効果的なJavaでのシリアル化に関する章を読んでいます。

  1. 誰がreadObject()とwriteObject()を呼び出しますか?これらのメソッドがプライベートとして宣言されているのはなぜですか?

  2. 以下は本からのコードの一部です

    // StringList with a reasonable custom serialized form
    public final class StringList implements Serializable {
        private transient int size = 0;
        private transient Entry head = null;
    
        //Other code
    
        private void writeObject(ObjectOutputStream s)
            throws IOException {
            s.defaultWriteObject();
            s.writeInt(size);
            // Write out all elements in the proper order.
            for (Entry e = head; e != null; e = e.next)
               s.writeObject(e.data);
            }
        }
    }
    

    size変数が一時的として宣言され、writeObjectメソッドで明示的に書き込まれる特定の理由はありますか?一時的なものとして宣言されていなかったら、とにかく書かれていたでしょう?

4

6 に答える 6

38

(1)メソッドはどのクラスまたはインターフェースでも宣言されていません。Serializableインターフェイスを実装し、シリアル化および逆シリアル化プロセス中に特別な処理を必要とするクラスは、これらのメソッドを実装する必要があり、シリアライザー/デシリアライザーはこれらのメソッドを反映しようとします。

これは、APIが実際にjavaDocで定義されているJavaのかなり奇妙なコーナーの1つです...しかし、メソッドがインターフェイスで定義されている場合は、それらを定義する必要ありましたpublic(インターフェイスメソッドを実装してロックすることはできません)private修飾子を追加することによって)。

なぜプライベートなのか-javaDocはヒントを与えません。おそらく、他のクラスはなく、実装者がそれらを使用することを意図しているため、それらはプライベートとして指定されます。それらは定義上プライベートです。

(2)この例は、特別な処理がどのように機能するかを示しています。この例では、sizeは一時的であり、シリアル化されません。しかし、ここで特別なハンドラーを導入すると、このハンドラーはの値をsizeストリームに追加します。非一時的なフィールドを使用する通常のアプローチとの違いは、結果のストリーム内の要素の順序である可能性があります(重要な場合...)。

一時フィールドがスーパークラスで定義されていて、サブクラスが値をシリアル化する必要がある場合、この例は理にかなっています。

于 2011-09-19T07:12:28.343 に答える
18

間違った関係者が使用してはならないことは別として、これらの方法のプライバシーのもう1つの理由は次のとおりです。

これらのメソッドがサブクラスによってオーバーライドされることは望ましくありません。代わりに、各クラスは独自のwriteObjectメソッドを持つことができ、シリアル化エンジンはそれらすべてを次々に呼び出します。これはプライベートメソッドでのみ可能です(これらはオーバーライドされません)。(同じことが当てはまりますreadObject。)

(これは、Serializableを実装するスーパークラスにのみ適用されることに注意してください。)

このようにして、サブクラスとスーパークラスは独立して進化し、古いバージョンの保存されたオブジェクトとの互換性を維持できます。

于 2011-09-19T14:43:30.727 に答える
11

readObject()/ writeObject()がプライベートであることについて、これが取引です。クラスBarがクラスFooを拡張する場合。FooはreadObject()/ writeObject()も実装し、BarはreadObject()/ writeObject()も実装します。

これで、Barオブジェクトがシリアル化または逆シリアル化されると、JVMはFooとBarの両方に対してreadObject()/ writeObject()を自動的に呼び出す必要があります(つまり、これらのスーパークラスメソッドを明示的に分類する必要はありません)。 privateの場合、メソッドのオーバーライドになり、JVMはサブクラスオブジェクトのスーパークラスメソッドを呼び出すことができなくなります。

したがって、それらはプライベートでなければなりません!

于 2012-11-21T13:44:31.733 に答える
7

およびはreadObject、クラスwriteObjectによって呼び出されます。Object(Input/Output)Stream

これらのメソッドは(独自のメソッドを実装する場合)プライベートとして宣言され(そして、そうである必要があります)、どちらのメソッドも実装によって継承およびオーバーライドまたはオーバーロードされないことを証明/示します。ここでの秘訣は、JVMが、対応するメソッド呼び出し中にいずれかのメソッドが宣言されているかどうかを自動的にチェックすることです。JVMは必要なときにいつでもクラスのプライベートメソッドを呼び出すことができますが、他のオブジェクトは呼び出すことができないことに注意してください。したがって、クラスの整合性が維持され、シリアル化プロトコルは通常どおり機能し続けることができます。

そして、トランジェントに関しては、intオブジェクトのシリアル化全体のシリアル化をそのまま制御しているだけです。ただし、すべてのフィールドが一時的なものである場合、技術的にはを呼び出す必要さえないことに注意してください。defaultWriteObject()ただし、柔軟性を確保するために呼び出すことをお勧めします。これにより、後で互換性を維持しながら、一時的でないメンバーをクラスに導入できます。

于 2011-09-19T06:49:29.020 に答える
0

一時変数に関しては、なぜ一時変数を宣言し、後でwriteobjectメソッドでシリアル化するのかを理解する最良の方法は、LinkedList / HashMap/etcクラスのreadobject/writeobjectメソッドをチェック/分析/デバッグすることです。

これは通常、クラス変数を事前定義された順序でシリアル化/逆シリアル化し、デフォルトの動作/順序に依存しない場合に実行されます。

于 2011-09-21T06:49:31.960 に答える
0

ソケットを参照するクラスAがあると仮定します。クラスAのオブジェクトをシリアル化する場合、SocketはSerializableではないため、直接シリアル化することはできません。この場合、以下のようにコードを記述します。

public class A implements  implements Serializable {

// mark Socket as transient so that A can be serialized

private transient Socket socket;

private void writeObject(ObjectOutputStream out)throws IOException {
    out.defaultWriteObject();

    // take out ip address and port write them to out stream
    InetAddress inetAddress = socket.getInetAddress();
    int port = socket.getPort();
    out.writeObject(inetAddress);
    out.writeObject(port);
}



private void readObject(ObjectInputStream in)
                  throws IOException, ClassNotFoundException{
    in.defaultReadObject();
    // read the ip address and port form the stream and create a frest socket.
    InetAddress inetAddress = (InetAddress) in.readObject();
    int port = in.readInt();
    socket = new Socket(inetAddress, port);
}
}

目的はwriteObject/readObjectメソッドの使用法を示すことであるため、ネットワーク関連の問題は無視してください。

于 2013-09-20T16:13:56.577 に答える