我想知道为什么Java编译器不信任这行代码:
List<Car> l = new ArrayList();
并期望有一个类型化的ArrayList:
List<Car> l = new ArrayList<Car>();
实际上,编译器指示第一种情况下未经检查的赋值。
为什么编译器没有看到刚刚创建了这个ArrayList(),所以不可能在其中找到除'Car'以外的一些对象?
如果之前创建了无类型的ArrayList,则此警告有意义,但在这种情况下不会...
实际上,由于List被输入'Car',所有期货“l.add('object')”只有在'object'是'Car'时才会被允许。 =&GT;所以,据我所知,不会发生任何意外。
我错了吗?
谢谢
答案 0 :(得分:4)
为什么编译器没有看到刚刚创建了这个ArrayList(),所以不可能在其中找到除'Car'以外的一些对象?
简单的答案是“因为它不是允许的。”
编译器必须实现Java语言规范。如果某些编译器编写者向编译器添加了一堆智能以允许“每个人都知道”的东西是安全的,那么他实际上所做的就是引入一个可移植性问题。使用此编译器编译和测试的代码在使用dumb(或更准确,严格符合)Java编译器编译时会产生编译错误。
那么为什么JLS不允许这样做呢?我可以想到几个可能的解释:
然后有一个相关的问题,即编译器是否可以实现这样的检查。我没有资格回答这个问题......但是我对这个问题了解得足以认识到解决问题并不像人们想象的那么简单。
答案 1 :(得分:2)
要添加到Stephen C的非常好的答案(主要是因为将其写为评论会非常麻烦,对不起),这个问题实际上是在JLS中明确提到的:
讨论
可以从any的值分配原始类型的变量 类型的参数实例。
例如,可以将
Vector<String>
分配给Vector, 基于子类型规则(§4.10.2)。从Vector到
Vector<String>
的反向分配是不安全的(因为 原始矢量可能有不同的元素类型),但仍然是 允许使用未经检查的转换(第5.1.9节)以启用 与遗留代码连接。在这种情况下,编译器将发出一个 未经检查的警告。
为什么他们没有特殊情况这个特例?因为如果你不需要在实现中添加特殊情况,并且“正确”解决方案不会增加任何特定问题(除了他们可能认为不太重要的一些写作工作) 。
此外,每一个特殊情况都意味着编译器变得更复杂(一般来说至少在这种情况下肯定是这样) - 考虑到javac总体上是多么简单,我认为拥有一个简单,快速的编译器并不是不可能的也是设计目标之一。