38

JEP 286中,我们看到我们将能够var在 JDK 10 (18.3) 中利用本地类型推断 ()。JEP 声明以下编译,这是预期的:

var list = new ArrayList<String>();  // infers ArrayList<String>

我很想知道如果我们尝试以下操作会发生什么:

var list = new ArrayList<>();

我在第二个片段中提出的建议甚至可以编译吗?如果是这样(我怀疑),会ArrayList接受Object它的泛型类型吗?

我会自己尝试,但我无法访问任何可以安装早期版本的机器。

谢谢!

4

3 回答 3

32

var的,钻石算子可以组合在一起。编译器将推断出最具体的泛型类型:

var list = new ArrayList<>(); // Infers ArrayList<Object>
var list = new ArrayList<>(List.of(1, 2, 3)); // Infers ArrayList<Integer>

你甚至可以将它们与匿名类结合起来:

var list = new ArrayList<>() {};
于 2018-01-24T18:13:21.850 回答
23

“合作”是一个模糊的问题,因此您可能会得到模糊的答案。

类型推断不是读心术;这只是约束解决。可用的类型约束越少,您就越有可能遇到失败或令人惊讶的结果(推断出您没有预料到的类型,例如Object.)

钻石说:我需要的类型可能已经存在于左侧,为什么要在右侧重复它们。

局部变量类型推断说:我需要的类型可能已经存在于右侧,为什么要在左侧重复它们。

通用方法调用说:我需要的类型可能已经存在于参数中,为什么要重复它们作为见证。

如果程序中有足够的类型信息可用,而左侧没有清单构造函数类型参数或目标类型,那么一切都会好起来的。例如:

List<String> anotherList = ...
var list = new ArrayList<>(anotherList);

在这里,编译器能够ArrayList通过查看构造函数(接受 的那个Collection<? extends E>)的参数类型来推断 的类型参数。所以它推断T=StringRHS,然后能够推断ArrayList<String>LHS。

换句话说,编译器将根据您提供的信息做它可以做的事情。你给它的信息越少,它就越有可能失败,或者不做你想做的事。

也就是说,我认为你问错了问题。你可以遗漏多少的问题不应该由“编译器让我遗漏多少”来驱动,而是“我对程序的可读性造成了多大的损害”。阅读代码比编写代码更重要。遗漏所有可能遗漏的内容不太可能最大限度地提高可读性。您应该努力留足够的内容,以确保没有读者在面对您的程序时感到困惑。

于 2018-03-01T14:12:25.097 回答
13

是的,它会编译。代码中的变量

var list = new ArrayList<>();

应推断为类型ArrayList<Object>(我相信由于擦除而无法准确确定元素的确切类型),这与使用以下代码相同:-

ArrayList list = new ArrayList<>(); 
// without the type of the element of list specified

list最终推断ArrayList<Object>为.


来自Brian邮件列表中的常见问题解答:-

如果我们要求双方都进行推理会发生什么?

如果你说:

var x = new ArrayList<>() 

那么你要求编译器推断 . 的类型参数List和 . 的类型x

但是您没有为编译器提供足够的类型信息来做好工作。

在大多数情况下,您会收到一个信息丰富的编译器错误,告诉您您要求阅读您的思想。在某些情况下,我们会退回到 inferring Object,就像我们目前所做的那样

Object o = new ArrayList<>()  // always inferred ArrayList<Object> here
于 2018-01-24T18:14:21.650 回答