简体   繁体   English

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

[英]Why diamond operator is used for Type Inference in Java 7?

List<String> list = new ArrayList(); will result in compiler warning. 将导致编译器警告。

However the following example compiles without any warning: List<String> list = new ArrayList<>(); 但是,以下示例编译时没有任何警告: List<String> list = new ArrayList<>();

I'm curious why introducing of diamond operator is needed at all. 我很好奇为什么需要引入钻石操作员。 Why not just have type inference on constructor if type argument is absent (as its already done for static methods in java and exploited by collection libraries like google guava) 如果不存在类型参数,为什么不在构造函数上进行类型推断(因为它已经针对java中的静态方法已经完成并且被像google guava这样的集合库利用)

EDIT : Using millimoose answer as starting point I looked what type erasure actually is and it's not just removing all type information. 编辑 :使用millimoose答案作为起点我查看了实际上是什么类型的擦除,它不只是删除所有类型信息。 Compiler actually does a bit more(copied from official doc ): 编译器实际上做了一些(从官方文档复制):

  • Replace all type parameters in generic types with their bounds or Object if the type parameters are unbounded. 如果类型参数是无界的,则将泛型类型中的所有类型参数替换为其边界或对象。 The produced bytecode, therefore, contains only ordinary classes, interfaces, and methods. 因此,生成的字节码仅包含普通的类,接口和方法。
  • Insert type casts if necessary to preserve type safety. 如有必要,插入类型铸件以保持类型安全。
  • Generate bridge methods to preserve polymorphism in extended generic types. 生成桥接方法以保留扩展泛型类型中的多态性。

The definitive answer would have to come from someone who designed that feature, but I'm assuming it's to distinguish this from using raw types, which make the compiler do something different altogether for the sake of compatibility. 确定的答案必须来自设计该功能的人,但我假设将其与使用原始类型区分开来,这使得编译器为了兼容性而完全不同。 An expression with a raw type in it is processed subtly differently than one that involves generics, an example is found in this SO question: Generic screws up non-related collection 其中包含原始类型的表达式与涉及泛型的表达式略有不同,在此SO问题中找到了一个示例: Generic screw up non-related collection

The Java developers try very hard to avoid changing the behavior of existing programs. Java开发人员非常努力地避免改变现有程序的行为。 List<String> list = new ArrayList(); does compile, and creates a raw ArrayList. 编译,并创建一个原始ArrayList。 If type inference were applied to it the result would be an ArrayList<String> , changing its behavior and possibly causing run time errors elsewhere in the program. 如果对其应用了类型推断,则结果将是ArrayList<String> ,从而更改其行为并可能导致程序中其他位置的运行时错误。

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

After further consideration, and a comment by @millimoose, I see that the changes in behavior would be local to the initializer, and detected at compile time. 经过进一步的考虑和@millimoose的评论后,我发现行为的变化对于初始化程序是本地的,并在编译时检测到。 Consider the following program: 考虑以下程序:

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);
  }
}

Without type inference, it runs and prints [3, 4] , despite the undesirable situation of a List<String> that contains Integer references. 在没有类型推断的情况下,它运行并打印[3, 4] ,尽管包含整数引用的List<String>的不良情况。

With type inference, it would not compile because the ArrayList(Collection<? extends E> c) does not allow use of a List<Integer> as argument when creating an ArrayList<String> . 使用类型推断时,它不会编译,因为ArrayList(Collection<? extends E> c)在创建ArrayList<String>时不允许使用List<Integer>作为参数。

This is part of an improvement to Java Generics in Java 7. 这是Java 7中Java Generics改进的一部分。
Before you would have had to write 之前你不得不写

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

Now you can write 现在你可以写了

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

Which is equivalent - the compiler will work it out for you. 这相当于 - 编译器会为您解决。 This is not the same as 这跟不一样

final List list = new ArrayList();

Which is an untyped List . 这是一个无类型List

The full syntax required by compiler of java 5 and 6 is: java 5和6的编译器所需的完整语法是:

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

They decided to simplify the syntax for us and allow not to write the same type parameters at both sides of assignment operator. 他们决定简化我们的语法,并允许不在赋值运算符的两边写入相同的类型参数。 However the <> operator is still required to make sure you understand what you are doing. 但是<>运算符仍然需要确保您了解自己在做什么。 By writing new ArrayList<>() you say "I understand I am creating instance of generic type and the generic parameter is as one I declared at the left side of the assignment." 通过编写new ArrayList<>()你会说“我理解我正在创建泛型类型的实例,并且泛型参数是我在赋值左侧声明的那个。”

The interesting cases are where calling the constructor with the diamond and as a rawtype successfully compiles but produces different code. 有趣的情况是使用菱形调用构造函数并且作为rawtype 成功编译但生成不同的代码。 Such examples are possible when mixed with the method overloading feature. 当与方法重载功能混合时,这样的示例是可能的。 IIRC, there's was an example somewhere on the OpenJDK coin mailing list (no, I'm not going to try to find it). IIRC,在OpenJDK硬币邮件列表上有一个例子(不,我不会试图找到它)​​。

It was not acceptable to have exactly the same code successfully come on Java SE 6 and Java SE 7 but produce different results. 在Java SE 6和Java SE 7上成功获得完全相同的代码是不可接受的,但会产生不同的结果。

For my money, I would have omitted the diamond and given a warning (treat as an error) if different code would have been produced by the inference algorithm chosen in 7 (essentially the same as for method generic-type inference from J2SE 5.0). 对于我的钱,如果7中选择的推理算法产生不同的代码(基本上与J2SE 5.0中的方法泛型类型推断相同),我会省略菱形并给出警告(视为错误)。 If you've written such code, it's probably non-obvious to work out if it's compileable or not anyway. 如果你已经编写了这样的代码,那么如果它是可编译的,那么它可能是不明显的。

If your project is built on maven, add the below in pom.xml under tag. 如果您的项目是在maven上构建的,请在标记下的pom.xml中添加以下内容。 It works perfectly.. <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> 它完美地工作.. <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>

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM