13
public class Test {
    public static class Nested<T> {
        public T val;
        Nested(T val) { this.val = val; }
    }
    public static void main(String[] args) {
        Nested<Integer> a = new Nested<Integer>(5);
        Nested<Integer> b = new Nested<Integer>(2);
        Integer diff = a.val - b.val;
    }
}

上記のコードは正常に動作します。ただし、Nested にメソッドを追加すると、次のようになります。

T diff(Nested<T> other) { return this.val - other.val; }

コンパイル エラーが発生します。

operator - cannot be applied to T,T

これは私には理にかなっています。T の型は実行時に消去されるため、Java は Integer などの特定のクラスに対してのみ定義されている演算子を適用できません。しかし、なぜ機能a.val - b.val するのですか?

編集:

良い答えがたくさん。みんな、ありがとう。その要点は、私が正しく理解していれば、コンパイラは Integer にキャストを追加できるということa.val - b.valです。ただし、ジェネリック関数定義の本体内で発生するため (ここで T はまだ何でもかまいません)、コンパイラは " " を機能させるために必要なキャストを追加できません。これは、より興味深い質問につながります。つまり、Java コンパイラがインライン化できる場合、diff のような一般的な関数が機能する可能性があるでしょうか?abNested<Integer>this.val - other.val-

4

5 に答える 5

9

2 つの違いは、ジェネリック メソッドの内側にいるか、外側にあるかです。

メソッド内が であることTがわかっていないIntegerため、マイナス演算子-は適用できません。ただし、main()一般的なメソッドの外にいる場合、コンパイラは、 でインスタンス化NestedIntegerたことを認識しているため、演算子の適用方法をよく知っています。ジェネリックの実装によって型が消去されて のコードが生成されたとしても、コンパイラはandに関しては考慮Nested<T>しません。適切なキャストを挿入し、結果をボックス化解除し、マイナス演算子を適用するのに十分な知識があります。abNested<T>-

于 2013-08-03T02:35:32.357 に答える
8

実行時エラーではなく、コンパイル時エラーが発生しています。

public static void main(String[] args) {
    Nested<Integer> a = new Nested<Integer>(5);
    Nested<Integer> b = new Nested<Integer>(2);
    Integer diff = a.val - b.val;
}

ここで、コンパイラは両方がであることを知っています。宣言したばかりです。TInteger<Integer>

T diff(Nested<T> other) { return this.val - other.val; }

ここで、コンパイラは について確信が持てませんT。それは何でもかまいません。そして、数値のみの演算子-は何に対しても許可されていません。

于 2013-08-03T02:36:16.923 に答える
1

a.val - b.val実行時ではなく、コンパイラによって検証されるため機能します。コンパイラは、 <Integer> を使用していることを「認識」し、コンパイルして実行します。実行時には、コンパイラがすでに検証しているため、消去しても問題はありません。

于 2013-08-03T02:34:33.687 に答える
1

メソッド呼び出しは実行時にa.val - b.val行われ、コンパイル時にチェックされるためです。

  • 最初のケースでは、コンパイラは型が でIntegerあり、- 操作が整数に対して許可されていることを認識しています。
  • 2 番目のケースでは、 の型がT事前にコンパイラに知られていないため、-操作が有効かどうかは不明です。したがって、コンパイラエラー。

diff(Nested<Book> other)本を他の本から差し引くことはできないので、この方法を使用すると考えてください。

于 2013-08-03T02:35:22.737 に答える
1

コードは Nested 内に存在しないため、型は既知です。コンパイラは、a.val - b.val が Integer から Integer を差し引いたものであり、自動ボックス化できることを明確に認識できます。コンパイラは本質的にそれを次のように書き換えます

Integer diff = Integer.valueOf(((Integer) a.val).intValue() - ((Integer) b.val).intValue())

.intValue および .valueOf の呼び出しは、自動ボックス化および自動ボックス化解除からのものです。

パラメーター化された型 Nested を使用したため、型キャストはコンパイラが安全に挿入できます。

確かに、技術的には、 aは Calendar オブジェクトのような別のものである可能性があります。これは、型が実行時に不明であるためです。しかし、ジェネリックを使用している場合、コンパイラは、ジェネリックを回避するためにばかげたことをしていないと信頼します。したがって、a.val または b.val が整数以外の場合、実行時に ClassCastException がスローされます。

于 2013-08-03T02:39:09.050 に答える