从JEP 286开始,我们看到我们将能够在JDK 10(18.3)中使用本地类型推断(var
)。 JEP表示以下编译,这是预期的:
var list = new ArrayList<String>(); // infers ArrayList<String>
我很想知道如果我们尝试以下内容会发生什么:
var list = new ArrayList<>();
我在第二个片段中提出的内容是否会编译?如果是这样(我怀疑),ArrayList
会接受Object
作为其通用类型吗?
我自己尝试一下,但是我无法访问任何可以在早期版本上安装的机器。
谢谢!
答案 0 :(得分:28)
是的,var
和钻石运营商可以合并在一起。编译器将推断出最具体的泛型类型:
var list = new ArrayList<>(); // Infers ArrayList<Object>
var list = new ArrayList<>(List.of(1, 2, 3)); // Infers ArrayList<Integer>
你甚至可以将它们与匿名课程结合起来:
var list = new ArrayList<>() {};
答案 1 :(得分:21)
“与...合作”是一个模糊的问题,因此您可能会得到模糊的答案。
类型推断不是介意阅读;这只是约束解决。可用的类型约束越少,您遇到失败的可能性就越大或结果令人惊讶(推断出您不期望的类型,例如Object
。)
Diamond说:我需要的类型可能已经出现在左侧,为什么在右侧重复它们。
局部变量类型推断说:我需要的类型可能已经存在于右侧,为什么在左侧重复它们。
通用方法调用说:我需要的类型可能已经存在于参数中,为什么重复它们作为见证。
如果程序中有足够的类型信息,而没有清单构造函数类型参数或左侧的目标类型,那么一切都会好的。例如:
List<String> anotherList = ...
var list = new ArrayList<>(anotherList);
这里,编译器能够通过查看构造函数的参数类型(ArrayList
)来推断Collection<? extends E>
的类型参数。因此,它在RHS上推断出T=String
,然后能够推断出LHS上的ArrayList<String>
。
换句话说,编译器会根据您提供的信息执行操作。你给它的信息越少,它就越有可能失败,或者没有做你想做的事。
那就是说,我认为你问了错误的问题。你可以遗漏多少的问题不应该由“编译器让我遗漏多少”来驱动,而是“我对程序的可读性造成了多大的伤害”。阅读代码比编写代码更重要。省去你可能遗漏的所有东西,不太可能最大限度地提高可读性。您应该努力将保留在中,以确保在遇到您的程序时没有读者感到困惑。
答案 2 :(得分:12)
是的,它会编译。代码中的var
var list = new ArrayList<>();
应推断为类型ArrayList<Object>
(我相信人们可能无法确定由于擦除而导致的元素的确切类型),这与使用如下代码相同: -
ArrayList list = new ArrayList<>();
// without the type of the element of list specified
其中list
最终被推断为ArrayList<Object>
。
来自Brian的FAQ on the mailing list: -
如果我们要求双方推断会怎样?
如果你说:
var x = new ArrayList<>()
然后你要求编译器 推断
List
的类型参数和x
的类型。但是你没有为编译器提供足够的类型信息来做好工作。
在大多数情况下,您会收到一个信息丰富的编译器错误告诉您 那是你要求你的思想被阅读。在某些情况下,我们会堕落 回到推断
Object
,正如我们目前使用:Object o = new ArrayList<>() // always inferred ArrayList<Object> here