Effective Javaを読むチャレンジ-項目11の3-

正しく機能するcloneの実装まとめ

長くなりましたがcloneは最後です。いままでだらだら書いてきた内容を中心にまとめます。

  • オーバーライドにより、CloneNotSupportedExceptionの宣言を削除することができる
  • cloneメソッドをオーバーライドするときは戻り値が自分自身のクラスであるpublicメソッドにする
  • cloneメソッドは最初にsuper.clone()を呼び出した後、必要なフィールドを修正する
  • 修正するフィールド(finalでない可変オブジェクト)は、基本的に深いコピー(deep copy)を行い、コピーしたオブジェクトへの参照にする
  • クラスが基本データ型か不変オブジェクトのフィールドしか持たないなら、フィールドの修正は不要
  • 上記には例外があり、シリアル番号やID、オブジェクトの生成時刻といったシステムで唯一無二なデータをコピーする場合は不変オブジェクトなどでもフィールドの修正は必要となる

これが冒頭で疑問に思ったことの答えでしょう。複雑で強制することが不可能な言語外のcloneの実装は、つまり、結局のところ、コンストラクタのように仕様上に定義されていて、単純に(呼び出すだけで)オブジェクト生成ができるわけではないということです。

筆者はこのような複雑なcloneの実装をするのでなければ、cloneでコピーする別の代替手段を提供するか、オブジェクトの複製を単に提供しない方が賢明と言っています。

cloneの代替手段 コピーコンストラクタとコピーファクトリー

cloneの代替手段として筆者が挙げているのが、コピーコンストラクタとコピーファクトリーです。コピーコンストラクタはこんな感じで、自分自身のクラスのみを引数にもつコンストラクタです。

コピーファクトリーも同様に、自分自身のクラスのみを引数にもつstaticファクトリーメソッドです。

オブジェクトのディープコピーは実務で何度か実装しましたが、巨大なフレームワークの中でcloneのオーバーライドを使おうっていう設計者はいませんでしたねえ・・・GoFのprototypeパターンはcloneメソッドを使ってますが、クラス関係はともかく、clone部分はこの実装方法とほぼ同じだった気がします。cloneについてはこれで終わります。

広告
  • LINEで送る