用于Java中看起来很奇怪的显式类型参数声明语法

And*_*Mao 14 java generics syntax types

我最近发现了在调用Java方法时显式声明泛型类型的奇怪语法.例如:

Collections.<String>emptyList();
Run Code Online (Sandbox Code Playgroud)

返回一个空的List<String>.但是,这看起来很愚蠢,因为实现<T> emptyList()只是未经检查的类型转换(List<T>) EMPTY_LIST,因此所有结果都具有相同的类型擦除(并且是相同的对象.)此外,通常不需要这种显式类型声明,因为编译器通常可以推断类型:

List<String> empty = Collections.emptyList();
Run Code Online (Sandbox Code Playgroud)

在做了一些挖掘之后,我发现了另外两次你想要使用这种语法,并且它们都是由于使用了Guava库并且显然试图在一行上放置太多语句.

  1. 装饰集合,例如使用同步包装器,并且编译器无法推断类型.如果您取出类型声明,则以下内容不起作用cannot convert from Set<Object> to Set<String>:

    Set<String> set = Collections.synchronizedSet(Sets.<String>newHashSet());
    
    Run Code Online (Sandbox Code Playgroud)
  2. 在编译器尝试创建过于具体的类型参数时,获取较少的特定类型参数.例如,如果没有类型声明,以下语句也会抱怨cannot convert from Map<String, String> to Map<String, Object>:

    Map<String, Object> toJson = ImmutableMap.<String, Object>of("foo", "bar");
    
    Run Code Online (Sandbox Code Playgroud)

我觉得具有讽刺意味的是,在第一种情况下,推断类型参数过于笼统,在第二种情况下它们过于具体,但我认为这只是Java中泛型系统的一个工件.

然而,除了在番石榴团队发明的这些奇怪的用例之外,这种语言结构本身似乎是可以避免的.此外,看似平淡,我认为那里编译器推断类型参数同时在上面的例子中的方式,而开发商只是选择不这样做.是否有在Java编程中使用此构造所必需或​​有用的示例,还是仅仅为了使编译器更简单/ JDK开发人员的生活更容易存在?

Mat*_*all 5

如何"关闭编译器"不是"必要或有用的"?我发现编译代码既有必要又有用.

有些时候,正如您已经发现的那样,无法推断出正确的类型.在这种情况下,有必要明确指定类型参数.编译器的一些例子不够智能:

如果您真的想深入了解类型推断的复杂性,它将以Java语言规范开始和结束.您将要关注JLS§15.12.2.7.根据实际参数§15.12.2.8推断类型参数.推断未解决的类型参数.

  • Java泛型具有许多缺陷,包括但不限于不完美类型推断,类型擦除,缺乏收集协方差等.在某些世界,当然,你的番石榴示例中的类型推断可能是可能的,但我们不会生活在那个世界中.编写Guava是为了使用这个世界上的Java编译器和有缺陷的泛型类型系统,所以我们使用我们已经拥有的东西. (2认同)