java - Generics Array Casting contradiction
问题描述
I'm facing a contradiction in how generics subtyping works. From my understanding, generics are nonvariant, so there should not be any subtyping relationship between the two.
Box<?> n = new Box<>(null);
Box<Object> error = (Box<T>) n; //error
Fails.
I understand that n
of compile time type Box<?>
can be type-casted to Box<T>
as a subtyping relationship of Box<T> <: Box<?>
exists. However since generics are invariant, i cannot assign a compile time type of Box<T>
to Box<Object>
.
With that in mind here comes the contradiction:
Box<T> g = new Box<>(t);
Box<Integer> fine = (Box<Integer>) g; //ok, but why?
It is strange because in the first example, we have shown that we cannot assign different generics together due to it being invariant. But in the 2nd example, I am able to do a type casting of compile type Box<T>
to Box<Integer>
.
though the 1 is an assignment and 1 is a typecasting operation, i would assume they work the same way. Is there a good explanation for this ?
Thanks in advance.
解决方案
需要明确的是,这在很大程度上是分配的问题,而不是演员表。
在您的第一个片段中
Box<?> n = new Box<>(null);
Box<Object> error = (Box<T>) n; //error
错误应该类似于
类型不匹配:无法转换
Box<T>
为Box<Object>
正如您所说,这试图告诉您 aBox<T>
不是 的子类型Box<Object>
,因此不能将赋值运算符右侧的表达式分配给error
。这基本上与中描述的问题相同
在你的第二个片段
Box<T> g = new Box<>(t);
Box<Integer> fine = (Box<Integer>) g; //ok, but why?
在分配方面,编译器没有发现任何错误。您将 type 的表达式分配给 typeBox<Integer>
的变量Box<Integer>
。
虽然 1 是一个赋值,而 1 是一个类型转换操作,但我会假设它们的工作方式相同。对此有很好的解释吗?
是的。Java语言规范声明
转换上下文允许转换表达式(第 15.16 节)的操作数转换为由转换运算符显式命名的类型。 与赋值上下文和调用上下文相比,强制转换上下文允许使用 §5.1 中定义的更多转换,并允许这些转换的更多组合。
JLS 继续解释允许哪些转换(另请参见5.1.6缩小引用转换,4.10子类型化),但短处是我们有一个未检查的缩小引用转换,这在赋值上下文中是不允许的。您可能还看到了编译器的警告
如果未检查缩小引用转换,则 Java 虚拟机将无法完全验证其类型正确性,可能导致堆污染(第 4.12.2 节)。为了向程序员标记这一点,未经检查的缩小引用转换会导致编译时未经检查的警告,除非被
@SuppressWarnings
(§9.6.4.5) 抑制。
这就是为什么你会看到这些行为。你可以在你的第一个片段中引入一个额外的演员来使它编译
Box<?> n = new Box<>();
Box<Object> error = (Box<Object>)(Box<T>) n; // error
这更能代表您在第二个片段中所做的事情(您会收到类似的警告)。
推荐阅读
- c# - 如何在 .net 上“发音”标点符号
- java - 为什么返回发生资源泄漏但我确实关闭了 Scanner(System.in)
- bash - 使用用户数据将 Web 访问日志发送到私有 S3 存储桶
- python - wxPython找不到属性
- automated-tests - 如何在守夜人中从其他测试文件运行文件的所有测试用例
- python - 检测非常微弱的圆圈,边缘不清晰。霍夫变换不起作用
- android - 具有自定义表面的 Android CameraX
- azure - 使用 Azure 存储模拟器进行 Dapr 本地开发
- python - 无法在python中搜索文件
- datasource - Grafana - 如何使用节点图面板和 influxdb 作为数据源