4

フォームのデータを処理するためのジェネリックメソッドを作成するときに、次のような(私が見ているように)予期しない動作に遭遇しました。次のコードが与えられます:

public class Test {
   public <T> void someGenericMethod(Integer a) {
      @SuppressWarnings("unchecked")
      T t = (T) a;
      System.out.println(t);
      System.out.println(t.getClass());
   }

   public static void main(String[] args) {
      Test test = new Test();
      test.<BigDecimal>someGenericMethod(42);
   }  
}

AFAIK、上記のコードClassCastExceptionは行にaを生成する必要がありT t = (T) aます。これは、mainのメソッド呼び出しがパラメーター化された型を設定し、BigDecimalBigDecimalからのキャストが許可されていないためです。予想とは逆に、プログラムは正常に実行され、次のように出力されます。Integer

42
class java.lang.Integer 

実際、メソッドシグネチャに別のパラメータ(などString b)を追加して別の割り当てを行うT t2 = (T) bと、プログラムは次のように出力します。

42
class java.lang.String 

t変数がタイプをに変更したのはなぜですかInteger(万が一、タイプTをオブジェクトに昇格させるためです)。

この振る舞いについての説明は大歓迎です

4

3 に答える 3

3

(T) aチェックされていないキャストです:タイプ eraserのため、ランタイムはタイプが何であるかを知る方法がないため、 type に属してTいるかどうかを実際にチェックすることはできません。aT

これを行うと、コンパイラは警告を発行します。あなたの場合、書き込みによってその警告を抑制しました@SuppressWarnings("unchecked")


追加するために編集されました(以下のコメントのさらなる質問に応えて):

キャストを確認したい場合は、次のように記述できます。

public class Test {
   public <T> void someGenericMethod(Class<T> clazz, Integer a) {
      T t = clazz.cast(a);
      System.out.println(t);
      System.out.println(t.getClass());
   }

   public static void main(String[] args) {
      Test test = new Test();
      // gives a ClassCastException at runtime:
      test.someGenericMethod(BigDecimal.class, 42);
   }
}

を渡すことでclazz、ランタイムがキャストをチェックできるようになります。さらに、コンパイラがTメソッドの引数から推論できるようにするため、test.<BigDecimal>someGenericMethodもう記述する必要はありません。

もちろん、メソッドを呼び出すコードは、未チェックのキャストを使用してこれを回避できます。

public static void main(String[] args) {
   Test test = new Test();
   Class clazz = Object.class;
   test.someGenericMethod((Class<BigDecimal>) clazz, 42);
}

しかし、それはmainのせいであり、のではありませんsomeGenericMethod。:-)

于 2012-08-30T21:04:10.247 に答える
2

コンパイルすると、上記のコードは基本的に次の非ジェネリック メソッドになります。

public void someGenericMethod(Integer a) {
   Object t = a;
   System.out.println(t);
   System.out.println(t.getClass());
}

キャストはありません。例外なし。

于 2012-08-30T23:52:26.567 に答える
1

メソッドシグネチャでタイプパラメータを指定しますが、決して使用しないでください。

私はあなたがこのようなものが欲しいと思います:

public class Test {
   public <T> void someGenericMethod(T someItem) {
      System.out.println(someItem);
      System.out.println(someItem.getClass());
   }
}

public static void main(String[] args) {
    Test test = new Test();
    BigDecimal bd = new BigDecimal(42);

    test.someGenericMethod(42);    // Integer
    test.someGenericMethod("42");  // String
    test.someGenericMethod(42L);   // Long
    test.someGenericMethod(bd);    // BigDecimal
}  

キャストする必要がないことに注意してください。

パラメータタイプはメソッドシグネチャで宣言され、パラメータから推測されます。

あなたのコードでは、メソッド呼び出し(私が見たことがない)をパラメーター化し、intを渡します。

サンプルコードは何もしないので、何をしようとしているのかを理解するのは少し難しいです。

于 2012-08-31T00:30:33.667 に答える