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

为什么在Java7中使用菱形运算符进行类型推断?,java,java-7,type-inference,diamond-operator,Java,Java 7,Type Inference,Diamond Operator,List List=new ArrayList()将导致编译器警告 但是,下面的示例编译时没有任何警告:List List=new ArrayList() 我很好奇为什么需要引入菱形算子。如果没有类型参数,为什么不在构造函数上进行类型推断呢(就像java中的静态方法已经做过的那样,并被google guava之类的集合库所利用) 编辑:以millimoose answer为起点,我了解了擦除的实际类型,它不仅仅是删除所有类型信息。编译器实际上做了更多的工作(复制自): 如果类型参数是无界的,则

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

但是,下面的示例编译时没有任何警告:
List List=new ArrayList()

我很好奇为什么需要引入菱形算子。如果没有类型参数,为什么不在构造函数上进行类型推断呢(就像java中的静态方法已经做过的那样,并被google guava之类的集合库所利用)

编辑:以millimoose answer为起点,我了解了擦除的实际类型,它不仅仅是删除所有类型信息。编译器实际上做了更多的工作(复制自):

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

这是对Java 7的改进的一部分。
在你不得不写作之前

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

这是一个非类型化的
列表

Java开发人员极力避免更改现有程序的行为<代码>列表=新建ArrayList()进行编译,并创建原始ArrayList。如果对其应用类型推断,结果将是一个
ArrayList
,改变其行为,并可能导致程序中其他地方的运行时错误

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

经过进一步的考虑,以及@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);
  }
}
import java.util.ArrayList;
导入java.util.List;
公开课考试{
公共静态void main(字符串[]args)引发异常{
列表整数=新的ArrayList();
整数.add(Integer.valueOf(3));
整数.add(Integer.valueOf(4));
列表=新的ArrayList(整数);
系统输出打印项次(列表);
}
}
在没有类型推断的情况下,它运行并打印
[3,4]
,尽管存在包含整数引用的
列表的不良情况


使用类型推断,它将不会编译,因为java 5和6编译器所需的
ArrayList(Collection完整语法是:

List List=new ArrayList();


他们决定为我们简化语法,并允许不在赋值运算符的两侧写入相同的类型参数。但是仍然需要
运算符来确保您理解所做的操作。通过编写
新ArrayList()
您可以说“我知道我正在创建泛型类型的实例,泛型参数与我在赋值左侧声明的参数相同。"

最终的答案必须来自于设计该功能的人,但我假设这是为了区别于使用原始类型,因为原始类型使编译器为了兼容性而做一些完全不同的事情。包含原始类型的表达式的处理方式与包含泛型的表达式(一种测试)的处理方式有细微的不同ple在这个问题中被发现:

有趣的例子是,使用菱形调用构造函数,作为一个rawtype成功编译了,但产生了不同的代码。当与方法重载功能混合使用时,这样的例子是可能的。IIRC,OpenJDK硬币邮寄列表中有一个例子(不,我不打算去找它)

让完全相同的代码在JavaSE6和JavaSE7上成功运行,但产生不同的结果是不可接受的


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

如果您的项目是基于maven构建的,请在pom.xml中的标记下添加以下内容。 它工作得很好。。
org.apache.maven.plugins
maven编译器插件
3.7.0
1.8
1.8

我假设这是为了区别于使用原始类型,因为原始类型使编译器为了兼容性而做了一些完全不同的事情。(包含原始类型的表达式的处理方式与包含泛型的表达式不同。)我可能同意millimoose的观点,但鉴于泛型在运行时被删除,引入新运算符(
)以实现编译器警告的向后兼容性是不对的。向后兼容性不是为了编译器警告。类似于
Object s=new arrarylist().get()的语句
与say
String s=new ArrayList().get()相比,右侧的结果类型的解析方式不同(使用预泛型算法)
。如果将
ArrayList
存储在中间变量中,这也适用。+1给出了泛型和原始变量之间差异的示例types@PhilippWendler“在最近的记忆中有这样一个问题,这才是我得出这个答案的真正原因,所以部分功劳也归于它的作者。”米利穆斯在仔细思考后说e、 我同意。行为的变化将是初始值设定项的局部变化,并在编译时检测到。我将编辑我的答案以显示一个示例。
final List list = new ArrayList();
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);
  }
}