[1899] Re:オーバーライド時の共変、反変について
投稿者:(ぱ)こと管理人
2015/02/24 02:39:59
はじめまして。最近この掲示板もすっかり閑散としてしまっていて、
投稿に気付くのが遅れてしまいました。すみません。
ご質問いただきありがとうございます。
引用の順番を変更しますが、結論から言えば、
>戻りの値の型が共変、引数の型が共変、
>ともにダウンキャストとなる、という認識ですが、
>なぜ、問題の有無の判断が変わってくるのでしょうか。
引数の型が共変なのはダウンキャストですが、
戻り値の型が共変なのはアップキャストだからです。
>”プログラミング言語を作る”内の8-3-5章にて
>下の解説を読みました。
p.289のコードですね。
>class ShapeArray{
> Shape get(int index);
> void set(int index, Shape shape);
>};
>
>class CircleArray extends ShapeArray{
> Circle get(int index); ・・・①
> void set(int index, Circle circle); ・・・②
>};
まず、このコードは、
p.249の補足で、JavaのArrayStoreExceptionの説明をしていますが、
JavaがArrayStoreExceptionを発生させるという実行時チェックを
しなければならなくなった、ということについて、共変の考え方からも
説明できる、ということを示すためのコードです。
ここまではよいでしょうか。
p.249の補足のサンプルコードで、
1: Line[] lines = new Line[10];
2: Shape[] shapes = lines;
3: shapes[3] = new Circle();
というコードがあったとき、Javaでは3行目でArrayStoreExceptionが
発生します。shapesはあくまでLineの配列であり、Circleの配列では
ないからです。
これはJavaにおける配列の話ですが、Javaの配列をShapeArrayとか
CircleArrayといったクラスで表現すると、p.289のコードのようになります。
ここで、CircleArrayのインスタンスcircleArrayがあったとして、
Shape shape = circleArray.get(i);
というコードは、アップキャストなので合法ですが、
circleArray.set(i, shape);
というコードは、ダウンキャストになります。CircleArray.set()の第2引数の
型はCircleなので、もしShapeを渡したければダウンキャストが必要になります。
Javaでは、このダウンキャストに相当する実行時例外が、ArrayStoreExceptionに
なっている、と言えるでしょう。
この例ではCircleArrayがShapeArrayを継承しているので、もし引数の共変を
許せば、
ShapeArray shapes = circleArray;
shapes.set(i, shape);
と書けてしまいます。このshapes.set(i, shape);が、
まさにp.249のコードの
shapes[i] = new Circle();
に相当するわけです。
これで回答になっているでしょうか?