5

我有下面的代码片段,这很好用。它不应该抛出编译时错误,因为我已经定义cArrayList它将包含String对象但我正在添加Integer对象。那么为什么它没有抛出编译时/运行时错误呢?

Collection c = new ArrayList<String>();
c.add(123);

我知道下面会抛出编译时错误,但为什么不在上面。这两个代码片段之间的逻辑区别是什么?

 Collection<String>() c = new ArrayList();
 c.add(123);
4

4 回答 4

6

第一个代码片段不会导致编译时错误,因为在该行

c.add(123)

编译器检查 c 的类型。由于您将c声明为Collection,因此编译器将其视为此类。由于Collection提供了一个方法add(Object),因此对于 c 的任何对象都是完全合理add的,尤其是整数。请注意,如果您尝试将集合值作为字符串读回,该程序导致运行时错误。

在您的第二个代码片段中,您提供了更多信息供编译器使用。在这个片段中,它知道Collection它处理的是一个Collection<String>,它只能接受Strings。因此,没有方法add(int)add(Object)只有add(String)。这会导致编译时错误。

于 2013-01-06T13:31:37.127 回答
3

为什么它没有抛出编译时错误?

因为它在语法或语义上不是无效的,所以它是不明智的。

请注意,大多数现代 IDE(例如 Eclipse)都可以配置为警告您有关未参数化的Collection c.,并且可以选择编译失败。

于 2013-01-06T13:28:25.197 回答
0

在第一个示例中,集合是“原始的”。这通常会导致警告而不是错误(取决于您的确切设置)。这是主要的,以便能够编译所有 Java 5 之前的遗留代码。

第二个示例,您将“原始”对象分配给参数化版本,这只能通过显式转换来完成。

于 2013-01-06T13:32:33.213 回答
0

1)逻辑上的区别是什么?

上图:可以在没有泛型类型的情况下声明 Collection。这称为原始类型。然后该集合可以保存任何类型的集合。由于使用原始类型集合,在运行时您可能会使用字符串集合作为整数集合,从而导致运行时异常,编译器通常会抛出警告。由于您没有在上面的示例中键入集合,因此编译器无法阻止这些运行时异常。如果您知道警告的用途并知道自己在做什么,则可以忽略该警告。

下图:但声明为 Collection<String> 的变量不能包含任何类型的集合。它必须是String 类型的集合。它是强类型。编译器将其视为错误是正确的。

2)为什么上面的代码段不会导致编译器错误?

Java 是强类型的,可确保类型安全。上面的代码片段不是类型安全的,但 Java 允许。这可能是出于历史原因:泛型仅在 Java 1.5 中引入,所以如果上面的代码片段会导致编译错误,那么大多数 Java 1.4 代码在 Java 1.5 编译器中都会被破坏。

并非每种编程语言都以这种向后兼容的方式发展(例如 PHP)。显然,在引入 Java 1.5 时,向后兼容性比类型安全更重要。

于 2013-01-06T13:35:31.283 回答