我最近遇到了在调用 Java 方法时显式声明泛型类型的奇怪语法。例如:
Collections.<String>emptyList();
返回一个空List<String>
。然而,这似乎很愚蠢,因为它的实现<T> emptyList()
只是未经检查的类型转换(List<T>) EMPTY_LIST
,因此所有结果都具有相同的类型擦除(并且是相同的对象)。此外,通常不需要这种显式类型声明,因为编译器通常可以推断类型:
List<String> empty = Collections.emptyList();
在进行了更多挖掘之后,我发现了另外两次你想要使用这种语法的地方,它们都是由于使用了 Guava 库并且显然试图在一行中放置太多语句。
装饰集合,例如使用同步包装器,编译器无法推断类型。如果您取出类型声明,则以下内容不起作用
cannot convert from Set<Object> to Set<String>
::Set<String> set = Collections.synchronizedSet(Sets.<String>newHashSet());
当编译器尝试生成过于具体的类型参数时,获取不太具体的类型参数。例如,如果没有类型声明,以下语句也会抱怨
cannot convert from Map<String, String> to Map<String, Object>
:Map<String, Object> toJson = ImmutableMap.<String, Object>of("foo", "bar");
我发现具有讽刺意味的是,在第一种情况下推断的类型参数过于笼统,而在第二种情况下它们过于具体,但我认为这只是 Java 中泛型系统的产物。
但是,除了Guava 团队发明的这些奇怪的用例之外,这种语言结构本身似乎是可以避免的。此外,在我看来,编译器有一种方法可以在上述两个示例中推断类型参数,而开发人员只是选择不这样做。是否有在 Java 编程中使用此构造的必要或有用的示例,或者它的存在仅仅是为了使编译器更简单/JDK 开发人员的生活更轻松?