90
104

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?

More than 5 years have passed since last update.

Javaのcloneメソッドの正しい実装方法

Last updated at Posted at 2015-02-22

cloneメソッドの実装を行うにはコツが必要なようなのでまとめてみたいと思います。

#cloneメソッドとは
cloneメソッドとは、Javaの全クラスの親クラスであるObjectクラスが持っているメソッドの一つで、自分自身を複製するという役割を持っています。

#cloneメソッドが必要な理由
自分自身を複製するのであれば、Hoge a=this;といった感じに記述すれば良いのではないか、と思われるかもしれません。しかし、Javaにおいて、クラス型の変数に入っているのは、インスタンスの中身への矢印(参照)なので、この場合、athisと全く同じインスタンスを指しているということになります。そのため、片方のフィールドを操作すると、もう片方のフィールドも書き換わってしまいます。このような事態を避けるためにcloneメソッドを利用する、というわけです。

#Objectクラスのcloneメソッド
##処理手順
Objectクラスのcloneメソッドの処理手順を大まかに示すと次のようになります。

  1. 複製するインスタンスのサイズを取得
  2. 新たなインスタンスの中身を生成
  3. 複製元のフィールドを丸ごとコピー

一見すると、これで完全な複製ができる、と思ってしまいますが、実はそうではありません。これは浅いコピーと呼ばれ、プリミティブ型の変数は複製されているものの、クラス型の変数は複製されていません。なぜなら、クラス型の変数の複製においては、インスタンスの中身への矢印(参照)を複製しているだけだからです。そのため、上で書いたのと同じことが起こってしまいます。
##特徴
Objectクラスのcloneメソッドは次のような特徴を持っています。

  • protected修飾子が付いている
  • Clonableインターフェイスを実装していないインスタンスを複製しようとした場合、CloneNotSupportedExceptionが投げられてしまう
  • 返り値がObject型である

なお、Clonableインターフェイスは、マーカーインタフェースと呼ばれる、中身が空のインターフェイスで、Clonableインターフェイスの場合には、__複製可能である__ということを示しています。

#cloneメソッドの正しい実装方法
以上のことから、cloneメソッドは次のようにオーバーライドするのが正しいということになります(Nodeクラスはcloneメソッドが正しくオーバーライドされているクラスとします)。

Example.java
public class Example implements Cloneable{ //Clonableインターフェイスを実装
    private static Node u; //クラス型static変数(static変数は元々インスタンスの中身がひとつしかないので、浅いコピーで良い)
    private Node s; //クラス型変数
    private int p; //プリミティブ型変数

    /*何らかのメソッドやコンストラクタが入る*/

    @Override
    public Example clone() { //基本的にはpublic修飾子を付け、自分自身の型を返り値とする
        Example b=null;

        /*ObjectクラスのcloneメソッドはCloneNotSupportedExceptionを投げる可能性があるので、try-catch文で記述(呼び出し元に投げても良い)*/
        try {
            b=(Example)super.clone(); //親クラスのcloneメソッドを呼び出す(親クラスの型で返ってくるので、自分自身の型でのキャストを忘れないようにする)
            b.s=this.s.clone(); //親クラスのcloneメソッドで深いコピー(複製先のクラス型変数と複製元のクラス型変数で指しているインスタンスの中身が違うコピー)がなされていないクラス型変数をその変数のcloneメソッドで複製し、複製先のクラス型変数に代入
        }catch (Exception e){
            e.printStackTrace();
        }
        return b;
    }
}

#関連記事

#参考文献

90
104
0

Register as a new user and use Qiita more conveniently

  1. You get articles that match your needs
  2. You can efficiently read back useful information
  3. You can use dark theme
What you can do with signing up
90
104

Delete article

Deleted articles cannot be recovered.

Draft of this article would be also deleted.

Are you sure you want to delete this article?