普段、Javaはあまり使わないほうですがJavaの型について学んだことがあったのでメモします。(触れるのはJavaですが、型の問題としては一般に関わる話です。)
BがAの部分型であるときにBの配列をAの配列の部分型にしてよいか
ということに関してです。
前提として、JavaはBがAを継承するとき、BがAの部分型といえます。 コードベースで説明します。
具体例
まず、Shape
とそれを継承する Circle
というclassを用意します。
public class Shape { public String name() { return "Shape"; } }
public class Circle extends Shape { public String name() { return "Circle"; } public String check() { return "OK!"; } }
このとき、 Circle
は Shape
を継承しており、 Circle
は Shape
の部分型となります。
部分型であるので以下のような代入が許容されます。
Shape s = new Circle();
Bの配列がAの配列の部分型
であることを許容するとき、以下のような代入を許容するということです。
Shape[] arr_s = new Circle[1];
さて、以下のコードはその配列の部分型を許容したコードです。
public class CheckArray { public static void main(String[] args) { Shape shape = new Shape(); Circle [] arr_circle = new Circle[1]; Shape [] arr_shape = arr_circle; arr_shape[0] = shape; Circle circle = arr_circle[0]; System.out.println(circle.check()); } }
このコードは問題が起きており、配列の部分型を許容したことで、最後の circle
は Shape
のオブジェクトで、check
というメソッドがありません。
それにも関わらず、実際のコンパイル時にはエラーが起こりません。
代わりに実行時には ArrayStoreException
というエラーが起こります。
本来であればコンパイル時でエラーを出したいところですが、Javaはこのミスに対処しておらず実行時にエラーを出すようにしたのだそうです。
ちなみに これに似たArrayList
というやつはコンパイル時にちゃんとエラーを出してくれるようです。
まとめ
悩ましくも面白い話だと思いました。