手持ちの参考書で不明点があります。
初心者で独学でやっており間違っている部分が多々あるかもしれませんが、宜しくお願いいたします。
#(1)cloneメソッドの中身
手持ちの参考書に「すべてのクラスはobjectクラスからcloneメソッドを継承している」とあるので、cloneの継承元(objectクラスのcloneメソッド)をeclipseで調べてみました。
すると『protected native Object clone() throws CloneNotSupportedException;』となっていて、cloneメソッドの中身は空っぽでした。
しかしこのnative修飾子を調べてみると、この修飾子のついたメソッドはjava以外の言語でどこかの場所で書かれているとのことなので、もしそうであれば、cloneメソッドを呼び出すだけでオーバーライドしなくても複製(ディープコピーできるかは別にして)できるはずだと思い、次のコード(参考書のコードを一部変更)で検証してみました。
<コード①>
java
1public class Main { 2 3 public static void main(String[] args) { 4 Hero h1 = new Hero(); 5 Hero h2 = h1.clone(); /* ここで複製 */ 6 System.out.println("コピー元のhpは" + h1.hp + "/コピー先のhpは" +h2.hp); 7 } 8}
java
1public class Hero implements Cloneable { 2 int hp ; 3 4 public Hero clone() { 5 Hero result = new Hero(); 6 //result.hp = this.hp; //★この行を無効化するとhpが複製されない 7 return result; 8 }
実行結果
コピー元のhpは100/コピー先のhpは0
ところが、Heroクラスの★の行(手持ちの参考書では有効化されている)を無効化すると、実行結果のとおりhpは0となっていて複製できていないことが分かりました。(★の行を有効化するとコピー先もhpは100になります)
このことから、cloneメソッドはインタンスの複製(Hero result = new Hero();)からフィールドの複製(result.hp = this.hp;)まで全て行ってあげないと複製できない。
そうなると、objectクラスのcloneメソッドの中身は本当に空っぽ(機能していない)なのでは?という疑問が出てきました。
そこで、ネットから拾った次のコード(一部変更)で再度検証してみました。
<コード②>
java
1import java.util.Arrays; 2public class Main { 3 public static void main(String[] args) { 4 5 MyClass mc1 = new MyClass(); 6 MyClass mc2 = mc1.clone(); 7 8 mc1.iArr[0] = 5; 9 10 System.out.println( 11 "mc1:" + mc1.n + " " + Arrays.toString(mc1.iArr) 12 + "\n" + 13 "mc2:" + mc2.n + " " + Arrays.toString(mc2.iArr) 14 ); 15 } 16}
java
1public class MyClass implements Cloneable { 2 3 public String n ="あ"; 4 public int[] iArr = {1, 2, 3}; 5 6 //cloneのオーバーライド 7 @Override 8 public MyClass clone() { 9 MyClass res = null; 10 11 try { 12 // クローン 13 res = (MyClass)super.clone(); 14 } catch (CloneNotSupportedException e) { 15 throw new InternalError(e.toString()); 16 } 17 // ディープコピー 18 //res.iArr = iArr.clone(); //有効化するとディープコピーになる 19 return res; 20 }
実行結果
mc1:あ [5, 2, 3]
mc2:あ [5, 2, 3]
すると今回は、フィールドのnもiArrもきちんと複製できていることが分かりました。
最初の<コード①>ではオーバーライドしてその中身も全て実装しないとインスタンスもフィールドも複製できなかったのに、今回の<コード②>ではオーバーライドはしているものの、『res = (MyClass)super.clone();』とcloneメソッドを呼び出すだけで複製に成功しています。
質問まとめ
(1)objectクラスのcloneメソッドの中身は本当に存在(機能)しているのでしょうか?存在(機能)していないのでしょうか?存在するならその内容の確認方法を教えていただけますでしょうか?
(2)最初の<コード①>では複製できないのに、今回の<コード②>では複製できているのはなぜでしょうか?
cloneメソッドの呼び出し方
<コード①>と<コード②>でのcloneメソッドの呼び出し方の違いについての疑問ですが、以下の理解で合っていますでしょうか?
もし違っていましたらご指摘・訂正いただけると助かります。
<コード①>では、Mainクラスからcloneメソッドを呼んでいる。(Hero h2 = h1.clone();の部分)
つまりMainクラスから複製したいクラス(Heroクラス)を経由して継承元(Objectクラス)を呼び出すことになるのでsuperを利用せずに呼び出している。
(インタンス外部からメソッド呼び出しがあった場合に子インスタンスにそのメソッドが存在しないときは親インスタンスのメソッドを探しにいく性質を利用している)
※cloneを呼ぶ流れ:①Mainクラス ⇒ ②複製したいクラス(Heroクラス)⇒ ③継承元(Objectクラス)
<コード②>では、複製したいクラスにcloneメソッドを書いているため、複製したいクラス(MyClassクラス)つまり自分自身から継承元(Objectクラス)を呼び出すことになるのでsuperを利用している。
※cloneを呼ぶ流れ:①複製したいクラス(MyClassクラス)⇒ ②継承元(Objectクラス)
まとめ:<コード①>と<コード②>もcloneメソッドを呼び出そうとしていることは同じで呼び出し方が違うだけ。