読者です 読者をやめる 読者になる 読者になる
無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

続・推論された型パラメータからClassを得る(JDKのコンパイラでは動作しなかった・・orz)

calicoさんより、推論された型パラメータからClassを得るのコードについてご指摘を頂いたので(ありがとうございます!)、いろいろと検証してみた。結論としては、上記日記のコードはEclipseコンパイラコンパイルしたクラスでしか期待通りの動作とならないようだ。

日記の検証で使用した以下のコードを、

package generics;

import java.util.LinkedList;
import java.util.ArrayList;

public class CreateInstance {

    public static void main(String[] args) 
    throws InstantiationException, IllegalAccessException {
        ArrayList<String>  list  = create();
    }
        
    /**
     * 指定された型のインスタンスを生成する。
     * 
     * @param <T> 型。デフォルトコンストラクタを持つこと。
     * @param src ※指定しないでください。
     * @return インスタンス
     * @throws InstantiationException インスタンス化できなかった場合
     * @throws IllegalAccessException アクセス権が内場合
     */
    static <T> T create( @Deprecated T... src ) 
    throws InstantiationException, IllegalAccessException {
        Class<T> cl = (Class<T>) src.getClass().getComponentType();
        return cl.newInstance();
    }
}

JDK1.6.0_07付属のコンパイラコンパイルしたクラスと、Eclipse(Eclipse Java Compiler 0.793_R33x, 3.3.2)でコンパイルしたものをそれぞれjavapにかけた場合以下の結果となる。(main関数のみ抜粋)

Eclipseでコンバイルしたクラス:

...
public static void main(java.lang.String[])   throws java.lang.InstantiationException, java.lang.IllegalAccessException;
  Signature: ([Ljava/lang/String;)V
  Code:
   0:   iconst_0
   1:   anewarray       #21; //class java/util/ArrayList ★
   4:   invokestatic    #23; //Method create:([Ljava/lang/Object;)Ljava/lang/Object;
   7:   checkcast       #21; //class java/util/ArrayList
   10:  astore_1
   11:  return
...

JDK付属のコンパイラコンパイルしたクラス:

...
public static void main(java.lang.String[])   throws java.lang.InstantiationException, java.lang.IllegalAccessException;
  Signature: ([Ljava/lang/String;)V
  Code:
   0:   iconst_0
   1:   anewarray       #2; //class java/lang/Object ★
   4:   invokestatic    #3; //Method create:([Ljava/lang/Object;)Ljava/lang/Object;
   7:   checkcast       #4; //class java/util/ArrayList
   10:  astore_1
   11:  return
...

ポイントは★をつけた部分のコードで、

このため、JDK付属のコンパイラコンパイルしたクラスでは、create()メソッド内の

Class<T> cl = (Class<T>) src.getClass().getComponentType();

で、java.lang.Objectのクラスが返されるため、ClassCastExceptionとなってしまう。

どっちのコンパイラの挙動が正しいのかまでは調べられていないけど、JDKコンパイラで使えないなら実質使えないなー。これは使えるテクニックだ!と思っていただけに残念。というかそもそも、EclipseコンパイラってJDKのモノと違うのかー。それすら知らなかった・・・。orz。