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

时间:2013-02-16 11:41:00

标签: java java-7 type-inference diamond-operator

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

但是,以下示例在没有任何警告的情况下进行编译:{{1​​}}

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

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

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

6 个答案:

答案 0 :(得分:8)

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

答案 1 :(得分:7)

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

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

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

import java.util.ArrayList;
import java.util.List;


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

没有类型推断,它会运行并打印[3, 4],尽管List<String>包含整数引用的情况不合适。

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

答案 2 :(得分:4)

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

final List<String> list = new ArrayList<String>();

现在你可以写

final List<String> list = new ArrayList<>();

这相当于 - 编译器会为您解决问题。这和

不一样
final List list = new ArrayList();

哪个是无类型List

答案 3 :(得分:4)

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

List<String> list = new ArrayList<String>();

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

答案 4 :(得分:1)

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

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

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

答案 5 :(得分:0)

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