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;
    }
}

上面的代码工作正常。但是,如果我向嵌套添加一个方法:

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 ina.val - b.val因为它知道a并且b被实例化为 as 。但是,由于发生在泛型函数定义的主体内(其中 T 仍然可以是任何东西),编译器无法添加使 " " 工作所需的强制转换。这就引出了一个更有趣的问题,即如果 Java 编译器能够内联,那么像 diff 这样的泛型函数是否可以工作?Nested<Integer>this.val - other.val-

4

5 回答 5

9

The difference between the two is whether you are inside a generic method or you are outside of it.

You got it absolutely right that inside the method T is not known to be an Integer, so operator minus - cannot be applied. However, when you are in main(), outside the generic method, the compiler knows that you've instantiated Nested with Integer, so it knows very well how to apply the operator. Even though the implementation of the generic has erased the type to produce the code for Nested<T>, the compiler does not think of a and b in terms of Nested<T>: it has enough knowledge to insert an appropriate cast, unbox the results, and apply the minus - operator.

于 2013-08-03T02:35:32.357 回答
8

You are getting a compile-time error, not a runtime one.

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;
}

Here, compiler knows that both T are Integer. You just declared <Integer>.

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

Here, compiler is not certain about T. It could be anything. And, numeric only operator - is not allowed for just anything.

于 2013-08-03T02:36:16.923 回答
1

Because method call is at runtime and a.val - b.val is checked at compile time.

  • In first case, compiler knows that the type is Integer and - operation is allowed for integers.
  • In second case, the type of T is not known to the compiler in advance, hence it is not sure whether - operation is valid or not. Hence the compiler error.

Consider we use the method as diff(Nested<Book> other) so there is no way a book can be subtracted from other.

于 2013-08-03T02:35:22.737 回答
1

Because the code doesn't live within Nested, the type is known. The compiler can clearly see that a.val - b.val is an Integer minus an Integer, which can be auto-boxed. The compiler essentially rewrites it to

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

The .intValue and .valueOf calls are from the auto-boxing and auto-unboxing.

The type casts are safe for the compiler to insert because you used a parameterized type Nested.

True, technically, a could be something else, like a Calendar object, since the type is unknown at runtime. But if you are using generics, the compiler trusts that you aren't doing anything dumb to circumvent it. Therefore, if a.val or b.val were anything other than Integers, a ClassCastException would be thrown at runtime.

于 2013-08-03T02:39:09.050 回答
1

a.val - b.val之所以有效,是因为它由编译器验证,而不是在运行时验证。编译器“看到”您正在使用 <Integer> 并且它编译并运行 好的,在运行时即使擦除也没有问题,因为编译器已经验证了这一点。

于 2013-08-03T02:34:33.687 回答