2011-10-31 41 views
1

我不知道为什么Java编译器不会在这行代码信任:通用集合不需要警告吗?

List<Car> l = new ArrayList(); 

,并希望有一个类型的ArrayList:

List<Car> l = new ArrayList<Car>(); 

事实上,编译器指示与第一种情况选中分配。

为什么编译器看不到这个ArrayList()刚创建好,所以不可能在其中找到'Car'以外的其他对象?

此警告才有意义,如果非类型化的ArrayList是之前创建的,但在这种情况下不...

实际上,由于列表的类型为“汽车”,所有期货“l.add(“对象')“只有在'object'是'Car'时才会被允许。 =>所以,据我所知,没有什么可能发生。

我错了吗?

感谢

+1

[Java 7中钻石运算符的重点是什么?](http://stackoverflow.com/questions/4166966/what-is-the-point-of-the-diamond-operator-in -java-7) – Thilo

+0

确实,这个问题非常相似。我没有看到它,谢谢。 – Mik378

回答

4

为什么不编译器看到此ArrayList()刚刚创建,所以它是不可能的,已经发现它比“汽车”等一些对象?

简单的答案是“因为它不是允许”。

编译器必须实现Java语言规范。如果一些编译器编写者去了并且为编译器添加了一堆智能以允许“每个人”都知道安全的事情,那么他实际上做了什么就是引入一个可移植性问题。使用该编译器编译和测试的代码在编译时会出现编译错误(或者更准确地说,严格遵守)的Java编译器。

那么为什么JLS不允许这样做呢?我可以想到几个可能的解释:

  • JLS编写者没有时间将其添加到规范中;例如考虑其他规范的所有后果。
  • JLS作者无法弄清楚声音的方式在说明书中表达这一点。
  • JLS编写者不想将某些东西放入规范中,他们不确定是否可以在真实世界的编译器中实现......不会对编译器编写者造成太大的负担。

然后还有一个编译器能否实现这样的检查的相关问题。我没有资格回答这个问题,但我对这个问题足够了解,意识到解决问题并不像想象中那么简单。

+0

那么这显然是可以实现的(即我可以编写一个预处理器,通过添加泛型来“修复”这个问题),但它肯定使编译器复杂化了很多。即你至少需要突然区分对象来自哪里或某物,因为从某个任意函数等返回的原始'LinkedList'显然不应该具有该特权。 – Voo

+0

我不会推荐使用预处理器来“解决”这个问题。首先,这意味着你的代码不再是真正的Java了。 Re:编译器的复杂性,这当然是真的。现在想象不得不将这些规则折叠到Java语言规范中。 –

+0

这不是我的观点。我只是说,如果使用预处理器运行很容易修复,那么您“可以”将它实现到编译器(最后一段)。直接将它实现到编译器当然是可行的,但是这取决于我们使用的是哪种解析器等等。 – Voo

2

为了增加斯蒂芬C'S真的很好的答案(主要是因为写这作为注释将是非常麻烦的,对不起),这个问题实际上是明确在JLS中提到:

讨论

变量可以从类型的参数实例的任何 的值中分配原始类型。

例如,可以根据子类型规则(§4.10.2)将Vector<String>指定给Vector, 。

来自Vector到Vector<String>反向分配是不安全的(因为 原始矢量可能有一个不同的元素类型),但仍是 ,以便利用未选中的转换(§5.1.9),以使 与传统的接口允许码。在这种情况下,编译器将发出未经检查的警告 。

为什么他们没有特例这种特殊情况?因为向实现添加特殊情况并不是你所做的事情,而且“正确的”解决方案不会增加任何特定的问题(除了一些他们认为不太重要的编写工作之外) 。

此外,每一个特殊情况都意味着编译器变得更加复杂(一般来说至少在本例中是这样肯定的) - 考虑到整体上javac是多么的简单,我认为拥有一个简单的,快速的编译器也是设计目标之一。