为什么在Java 7中使用菱形运算符进行类型推理?

List list = new ArrayList(); 将导致编译器警告。

但是,以下示例在没有任何警告的情况下编译: List list = new ArrayList();

我很好奇为什么需要引入钻石操作员。 如果没有类型参数,为什么不在构造函数上进行类型推断(因为它已经针对java中的静态方法已经完成并且被像google guava这样的集合库利用)

编辑 :使用millimoose答案作为起点我查看了实际上是什么类型的擦除,它不只是删除所有类型信息。 编译器实际上做了一些(从官方文档复制):

  • 如果类型参数是无界的,则将generics类型中的所有类型参数替换为其边界或对象。 因此,生成的字节码仅包含普通的类,接口和方法。
  • 如有必要,插入类型铸件以保持类型安全。
  • 生成桥接方法以保留扩展generics类型中的多态性。

确定的答案必须来自设计该function的人,但我假设将其与使用原始类型区分开来,这使得编译器为了兼容性而完全不同。 其中包含原始类型的表达式与涉及generics的表达式略有不同,在此SO问题中找到了一个示例: Generic screw up non-related collection

Java开发人员非常努力地避免改变现有程序的行为。 List list = new ArrayList(); 编译,并创建一个原始ArrayList。 如果对其应用了类型推断,则结果将是ArrayList ,从而更改其行为并可能导致程序中其他位置的运行时错误。

================================================== ==========================

经过进一步的考虑和@millimoose的评论后,我发现行为的变化对于初始化程序是本地的,并在编译时检测到。 考虑以下程序:

 import java.util.ArrayList; import java.util.List; public class Test { public static void main(String[] args) throws Exception { List integers = new ArrayList(); integers.add(Integer.valueOf(3)); integers.add(Integer.valueOf(4)); List list = new ArrayList(integers); System.out.println(list); } } 

在没有类型推断的情况下,它运行并打印[3, 4] ,尽管包含整数引用的List的不良情况。

使用类型推断时,它不会编译,因为ArrayList(Collection c)在创建ArrayList时不允许使用List作为参数。

java 5和6的编译器所需的完整语法是:

List list = new ArrayList();

他们决定简化我们的语法,并允许不在赋值运算符的两边写入相同的类型参数。 但是<>运算符仍然需要确保您了解自己在做什么。 通过编写new ArrayList<>()你会说“我理解我正在创建generics类型的实例,并且generics参数是我在赋值左侧声明的那个。”

这是Java 7中Java Generics改进的一部分。
之前你不得不写

 final List list = new ArrayList(); 

现在你可以写了

 final List list = new ArrayList<>(); 

这相当于 – 编译器会为您解决。 这跟不一样

 final List list = new ArrayList(); 

这是一个无类型List

有趣的情况是使用菱形调用构造函数并且作为rawtype 成功编译但生成不同的代码。 当与方法重载function混合时,这样的示例是可能的。 IIRC,在OpenJDK硬币邮件列表上有一个例子(不,我不会试图找到它)​​。

在Java SE 6和Java SE 7上成功获得完全相同的代码是不可接受的,但会产生不同的结果。

对于我的钱,如果7中选择的推理算法产生不同的代码(基本上与J2SE 5.0中的方法generics类型推断相同),我会省略钻石并给出警告(视为错误)。 如果你已经编写了这样的代码,那么如果它是可编译的,那么它可能是不明显的。

如果您的项目是基于maven构建的,请在标记下的pom.xml中添加以下内容。 它完美地工作.. org.apache.maven.plugins maven-compiler-plugin 3.7.0 1.8 1.8