ほろ酔い開発日誌

有意義な技術的Tipsを共有出来たら嬉しいです。Ruby、Railsが好きです。Web開発全般(Rails多め、フロント、サーバー、インフラ)、データ分析、機械学習あたりの記事が中心になる予定です。

Java 配列部分型 ( ArrayStoreException )

普段、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!"; }
}

このとき、 CircleShape を継承しており、 CircleShape の部分型となります。

部分型であるので以下のような代入が許容されます。

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());
  }

}

このコードは問題が起きており、配列の部分型を許容したことで、最後の circleShapeのオブジェクトで、checkというメソッドがありません。

それにも関わらず、実際のコンパイル時にはエラーが起こりません。 代わりに実行時には ArrayStoreException というエラーが起こります。

本来であればコンパイル時でエラーを出したいところですが、Javaはこのミスに対処しておらず実行時にエラーを出すようにしたのだそうです。 ちなみに これに似たArrayList というやつはコンパイル時にちゃんとエラーを出してくれるようです。

まとめ

  • Javaコンパイル時に配列の部分型を許容してしまっているが本来はコンパイル時にエラーを出すべき。
  • Javaはその代わりに ArrayStoreException というエラーを実行時に出す。

悩ましくも面白い話だと思いました。