うさぎ組

ソフトウェア開発、チームによる製品開発、アジャイル、ソフトウェアテスト

全ての配列はObjectのサブクラスである

先日、こんなコードを実行すると例外が発生して混乱しました。

Object[] obj = piyo();

for(Object each : obj){
  execute(each);
}

piyo()では様々なオブジェクトを配列にして返してくるのでこのようになっていて、
execute(Object obj)で受けとって処理するような実装です。
これを実行するとexecute内の処理でClassCastExceptionが発生していました。
executeに渡したeachが配列になっていて、直接キャストできなかったからでした。
ただし、コンパイルエラーは出ていません。あくまで実行時例外です。


調べるとpiyo()はObjectを返すようになっていました。
とすると

Object[][] obj = piyo();

じゃないとコンパイルエラーになるはず。。。と思います。
でも実際にはなっていません。
例えばStringを返すhoge2()があったときは

String[][] str = hoge2();

でなければならず、

String[] str = hoge2();

ではコンパイルエラーになります。

で、記憶の遥かかなたにあったかけらと一緒にJavaの言語仕様を見ると次のような記述がありました。


Every array has an associated Class object, shared with all other arrays with the same component type. The direct superclass of an array type is Object. Every array type implements the interfaces Cloneable and java.io.Serializable.

http://java.sun.com/docs/books/jls/third_edition/html/arrays.html#10.8

つまり、配列のスーパークラスはObjectクラスである、と。

実際にコードにすると次のようになります。

public class Main {
    public static void main(String[] args) {

       //素直に書くとこうなる
        Object[] o1 = new Object[2];
        Object[][] o2 = new Object[2][2];
        String[] s1 = new String[2];
        String[][] s2 = new String[2][2];
        int[] i1 = new int[2];
        int[][] i2 = new int[2][2];
 
        //配列は全てObjectクラスのサブクラスなのでこう書くこともできる
        Object objArray1 = new Object[2];
        Object objArray2 = new Object[2][2];
        Object strArray1 = new String[2];
        Object strArray2 = new String[2][2];
        Object intArray1 = new int[2];
        Object intArray2 = new int[2][2];
 
        System.out.println("objArray1 : " + objArray1.getClass().getSimpleName());
        System.out.println("objArray2 : " + objArray2.getClass().getSimpleName());
        System.out.println("strArray1 : " + strArray1.getClass().getSimpleName());
        System.out.println("strArray2 : " + strArray2.getClass().getSimpleName());
        System.out.println("intArray1 : " + intArray1.getClass().getSimpleName());
        System.out.println("intArray2 : " + intArray2.getClass().getSimpleName());
    }
 
}

で、実行結果は

objArray1 : Object[]
objArray2 : Object[][]
strArray1 : String[]
strArray2 : String[][]
intArray1 : int[]
intArray2 : int[][]

 ここで実行できます→ http://ideone.com/Um7tv


Twitterでツイートしたときに、すぐにJLSのページを教えてくれたid:rf0444(@rf0444)さんありがとうございました!