effective java 輪読会 項目77-78
TRANSCRIPT
Effective Java 輪読会2014/03/19
開発部 田中
項目 77
インスタンス制御に対しては、 readResolve より enum 型を選ぶ
readResolveによるインスタンス制御
• シングルトンをシリアライズする場合の伝統的な方法o 自身の持つシングルトンインスタンスを返すような readResolveメソッドを定義することで、デシリアライズによって生成されたインスタンスは破棄し、常にメモリ上に存在するインスタンスの参照を返す。
インスタンス制御する場合のtransient
• readResolveによって常にメモリ上のインスタンスを返すのなら、シングルトンクラスのインスタンスフィールドをシリアライズの対象にする必要はない。→ transient修飾子を付与する
攻撃に備えて transientを付与する
• むしろ readResolveによってシリアライズされるクラスのインスタンスフィールドはtransientにすべき
• readResolveが呼ばれる前に、デシリアライズによって生成されたインスタンスの参照を「盗む」ことができてしまう。
実際に参照を盗んでみる
enumを使う
• readResolveによるインスタンス制御は、廃れてはいないが、十分な注意が必要
• そこで、 enumを使えば、シングルトン特性を JVMが保証してくれる
• enumが使えない場合もある
readResolveのアクセス可能性
• デシリアライズは、クラス階層の上から行われる。
• スーパークラスのインスタンスが生成されて ClassCastExceptionが発生しないように気をつける
まとめ
• シリアライズのインスタンス制御には、可能な限り enumを使う
• readResolveメソッドによるインスタンス制御の場合は、インスタンスフィールドがプリミティブ型か、 transientであることを確認する
項目 78
シリアライズされたインスタンスの代わりに、シリアライズ・プロキシを検討する
・シリアライズ・プロキシ・パターンとは・ writeReplace と readResolve
なぜ使うか
• ネストしたクラスに、エンクロージングクラスの論理的状態を表現する
• シリアライズ・プロキシから元のクラスのインスタンスに復元する際に、元のクラスのコンストラクタを使用できる• 言語機能によってデシリアライズを制御できる
ポイント 1: writeReplace
• エンクロージングクラスをシリアライズ・プロキシへ変換する(シリアライズ・プロキシクラスの形式でシリアライズする)
ポイント 2: readResolve
• シリアライズ・プロキシクラスにreadResolveを実装する
• デシリアライズの際にシリアライズ・プロキシをエンクロージングクラスのインスタンスにエンクロージングクラスのコンスタラクタを使って変換する。
readResolveの柔軟性
• readResolveでは publicの APIのみを使用してインスタンスを生成できる
• staticファクトリーメソッドも使える
• 実際にどのクラスのインスタンスを返すか制御できる。• ex. EnumSet
まとめ
• finalクラスについて、 readObjectやwriteObjectを書く必要がある場合には、シリアライズ・プロキシ・パターンを検討する
• クラスの不変式をシリアライズするための簡単・確実な方法