【Java】clone() を使ったサブクラスを含むオブジェクト複製 
2014/01/04 Sat [edit]
Java のオブジェクトコピーには少し落とし穴があるね。代入式や関数の引数などでも、値渡しか参照渡しか気をつけなきゃいけないけど(C言語などは&や*[ポインタ]を付けたりするから分かりやすいが)、clone() もそんな感じ。ボタンなど同じオブジェクトが並ぶものを clone() してみたが、実はこのボタンは角丸矩形とグラデーション、外枠、テキスト描画を画像化して、ボタンのように使えるクラスを自作したものだったりする。色々なオブジェクトが混ざってるので、一筋縄ではいかなかった(笑)。
とりあえず、簡単な実装例(コードは適当なものなので、良し悪しは考えないよう(笑))。
例えば元が次のようなクラスとすると、
public class SuperClass {
public int x, y;
public String text = "テキスト";
public SuperClass(int x, int y) {
this.x = x;
this.y = y;
}
}
Object クラスの clone() を実装するには、
public class SuperClass implements Cloneable {
public int x, y;
public String text = "テキスト"; //←ここはあまり問題ない
public SuperClass(int x, int y) {
this.x = x;
this.y = y;
}
@Override
public SuperClass clone() {
try {
return (SuperClass)super.clone(); //←自身のクラスでキャストしておくと良い
} catch (CloneNotSupportedException e) {
throw new RuntimeException();
}
}
}
のように Cloneable を implements して clone() を public スコープにして @Override する。return の値は自身のクラスのキャストしておいた方が良いね。
とりあえずこれで、
SuperClass obj1 = new SuperClass(10, 20);
SuperClass obj2 = obj1.clone();
のように使える。でも実際のクラスはもう少し複雑で、継承を使ってたりする場合は、そのサブクラスを、
public class SubClass extends SuperClass {
public int w, h;
public Bitmap image; //←参照なので問題あり
public int[] data = new int[]{ 1, 2, 3, 4 }; //←参照なので問題あり
public SubClass(int x, int y, int w, int h) {
super(x, y);
this.w = w;
this.h = h;
}
@Override
public SubClass clone() {
return (SubClass)super.clone();
}
}
みたいにすれば、同じように SubClass.clone() が使えるが、気を付けなければいけないのは、オブジェクトは参照になっているということ。つまり、
SubClass obj3 = new SubClass(10, 20, 30, 40);
SubClass obj4 = obj3.clone();
obj4.data[0] = 100; //→ obj3.data[0] も 100 になる
Paint p = new Paint();
p.setColor(Color.YELLOW);
Canvas c = new Canvas(obj4.image);
c.drawText("Debug", 3, 22, p); //→ obj3.image にも"Debug"が描かれる
のように、内容を書き換えてみると、下画像ような事が起こる。

できれば画像や配列なども別々のオブジェクトとして扱いたい場合は、少しだけ手を加えておくと良い。例えば、
public class SubClass extends SuperClass {
public int w, h;
public Bitmap image;
public int[] data = new int[]{ 1, 2, 3, 4 };
public SubClass(int x, int y, int w, int h) {
super(x, y);
this.w = w;
this.h = h;
}
@Override
public SubClass clone() {
SubClass obj = (SubClass)super.clone();
obj.data = data.clone(); //clone() が使えるなら複製
obj.image = image.copy(Config.ARGB_8888, true); //clone()が無いなら、無理矢理複製(笑)
return obj;
}
}
のように戻値のオブジェクトも複製すれば、別々のものとなる。つまり必要なものだけ clone() を実装しておけば、少しだけ楽に複製できるという事だね。あくまで簡単な例だけど、これだけで十分事足りる。
※プロパティが全て public になってるのは getter, setter 省略のため。
- 関連記事
トラックバック
トラックバックURL
→http://fantom1x.blog130.fc2.com/tb.php/101-e50d2c1c
この記事にトラックバックする(FC2ブログユーザー)
| h o m e |