简体   繁体   English

无法将有效常量(值)分配给通用类型变量

[英]Cannot assign valid constant(value) to a Generic Type variable

Why does the following not work?为什么以下不起作用?

void execute() {
 Integer a = Integer.valueOf(1);

 a = reassign(a);

 D.log("a: " + a);
}

<T extends Integer> T reassign(T t) {
  t = Integer.valueOf(2); // error: incompatible types: Integer cannot be converted to T
  // t = (T) Integer.valueOf(2); // This works but with  warning: [unchecked] unchecked cast
  return t;
}

<T extends Integer> T reassign2(T t, T anotherT) {
  t = anotherT; // This works without any warning.
  return t;
}

My understanding is that generic methods/classes/interfaces will be compiled to a single class file where the type parameter is replaced with most appropriate lower bound (Integer in the above case).我的理解是泛型方法/类/接口将被编译为单个 class 文件,其中类型参数被替换为最合适的下限(在上述情况下为整数)。

Java env: java 11.0.4 2019-07-16 LTS Java 环境:java 11.0.4 2019-07-16 LTS

My understanding is that generic methods/classes/interfaces will be compiled to a single class file where the type parameter is replaced with most appropriate lower bound我的理解是泛型方法/类/接口将被编译为单个 class 文件,其中类型参数替换为最合适的下限

Your understanding is correct, but compilers are designed to handle generics more intelligently.您的理解是正确的,但编译器旨在更智能地处理 generics。 If compilers are designed exactly the way you described, what's the point of generics?如果编译器完全按照您描述的方式设计,那么 generics 有什么意义? I could just write a method taking an Integer instead.我可以只写一个采用Integer的方法。 There's no need for generics, since the compiler will just replace whatever type parameter I have with Integer anyway.不需要 generics,因为无论如何编译器只会Integer替换我拥有的任何类型参数。

You have specified that T must be Integer or a subclass of Integer .您已指定T必须是IntegerInteger的子类。 Think about the situation when T is a subclass of Integer , would the following assignment still work?想想当TInteger的子类时的情况,下面的赋值仍然有效吗? It wouldn't!它不会!

t = Integer.valueOf(2); // you are assigning an instance of a superclass to a subclass variable

You could argue that Integer cannot have any subclasses as it is final , but the compiler is not designed to check for the final ness of classes in this situation.您可能会争辩说Integer不能有任何子类,因为它是final ,但编译器并非旨在检查这种情况下类的final性。 Using Integer as a bound here probably means that reassign shouldn't be generic at all.在这里使用Integer作为界限可能意味着reassign根本不应该是通用的。


Another thing that the compiler do is to insert casts where necessary, but that's not really relevant to this question.编译器做的另一件事是在必要时插入强制转换,但这与这个问题并不真正相关。

The reason why it doesn't work is because the compiler can't prove that T is actually and not a subtype of T .它不起作用的原因是编译器无法证明T实际上是而不是T的子类型。 Integer is a bad example here because it is final and no one can extend it but the compile is not smart enough to know that and reason about it. Integer 在这里是一个不好的例子,因为它是最终的,没有人可以扩展它,但是编译器不够聪明,无法知道这一点并对其进行推理。

Imagine you have the following想象一下你有以下

 class Foo{
 }

 class Bar extends Foo {
 }

and you call reassign like this你像这样调用重新分配

reassign(new Bar());

Where reassign was allowed to do允许重新分配的地方

<T extends Foo> T reassign(T t){
    t = new Foo();
    return t;
}

then this would be equivalent of saying那么这相当于说

Bar b = new Foo()

Which is not valid of course这当然是无效的

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM