6

受け取ったリスト内の各項目のゲッターを実行するジェネリックを使用した次のメソッドがあります。

public static <T, S> List<S> getValues(List<T> list, String fieldName) {
    List<S> ret = new ArrayList<S>();
    String methodName = "get" + fieldName.substring(0, 1).toUpperCase()
            + fieldName.substring(1, fieldName.length());
    try {
        if (list != null && !list.isEmpty()) {
            for (T t : list) {
                ret.add((S) t.getClass().getMethod(methodName).invoke(t));
            }
        }
    } catch (IllegalArgumentException e) {
    } catch (SecurityException e) {
    } catch (IllegalAccessException e) {
    } catch (InvocationTargetException e) {
    } catch (NoSuchMethodException e) {
    }
    return ret;
}

次のように呼び出すと、完全に正常に動作します。

List<Integer> ids = getValues(List<MyDTO>, "id");
request.setListIds(ids);

ただし、1 行で実行するとコンパイル エラーが発生します。

request.setListIds(getValues(List<MyDTO>, "id"));

エラーは言う:

タイプ MyDTO のメソッド setListIds(List-Integer-) は、引数 (List-Object-) には適用されません。

そのため、リストを直接設定しようとすると、ジェネリックが整数ではなくオブジェクトにキャストされます。何故ですか?

4

4 に答える 4

1

明らかに、コンパイラはジェネリック型変数を正しく推測していません。割り当てでは、彼は を正しく推測しS=Integerていますが、結果をパラメーターとして渡すときは、メソッド パラメーターのジェネリック型が考慮されていません。

setListIds(List)これは、実行時のメソッドのシグネチャがではなくであるため、型消去が原因ですsetListIds(List<Integer>)。ちなみに、同じ質問がここで尋ねられました。その答えは、コンパイラがそのように動作する理由を説明しています。

于 2013-11-12T11:24:58.793 に答える
1

タイプ erasureのため、メソッドの実際のコンパイル済みバイトコードではキャストは行われませんでした。

バイトコードを生成するとき、コンパイラは、パラメーター型の変数を、そのパラメーター型の上限と同じ型を持つものとして、またはObject型が無制限の場合に扱います。したがってS、メソッドに制約がある場合<S extends Integer>、コンパイラは へのキャストを挿入しIntegerます。ただし、S無制限であるため、への参照Sはバイトコード内で型として扱われObjectます。したがって、キャストはありません。

メソッドを記述したとおりに使用すると、メソッドを呼び出すときに型パラメーターを入力することで、コンパイル エラーを取り除くことができます。

YourClass.<MyDTO, Integer>getValues(list, "id")

これは不格好に見えますが、おそらく type parameter を取り除くのがよいでしょうT

于 2013-11-12T11:25:49.227 に答える