关于参数化类型的通用 static 工厂方法
您似乎想编写方便的工厂方法来实例化泛型集合。
您可以编写如下泛型方法:
public static <T> List<T> newArrayList() {
return new ArrayList<T>();
}
public static <K,V> Map<K,V> newHashMap() {
return new HashMap<K,V>();
}
那么你可以简单地写:
// absolutely type-safe!!! no compilation warnings at all!!!
List<String> names = newArrayList();
List<Integer> nums = newArrayList();
Map<String, List<String>> map = newHashMap();
请注意,在某些情况下,上述方法不必是 static,您可以选择在方法中省略实现 class 的名称,而仅使用 interface 名称(例如 @987654352 @, newMap)。
Effective Java 2nd Edition 的认可
这种泛型类型推断static工厂方法其实是Effective Java 2nd Edition认可的;它有幸成为书中讨论的第一个项目。
以下是来自第 1 项的相关引用:考虑static 工厂方法而不是构造函数:
static 工厂方法的第四个优点是它们减少了创建参数化类型实例的冗长性。
当您调用参数化类的构造函数时,不幸的是,您必须指定类型参数,即使它们在上下文中是显而易见的。这通常需要您快速连续提供两次类型参数:
Map<String,List<String>> m =
new HashMap<String,List<String>>();
随着类型参数的长度和复杂性的增加,这种多余的规范很快就会变得很痛苦。但是,使用static 工厂,编译器可以为您找出类型参数。这称为类型推断。例如,假设HashMap 提供了这个static 工厂:
public static <K,V> HashMap<K,V> newInstance() {
return new HashMap<K,V>();
}
然后你可以用这个简洁的替代方案替换上面冗长的声明:
Map<String,List<String>> m = HashMap.newInstance();
不幸的是,在 1.6 版中,HashMap 等标准集合实现没有 static 工厂方法,但您可以将这些方法放在您自己的实用程序类中。更重要的是,您可以在自己的参数化类中提供此类 static 工厂。
该项目还规定了这些static 工厂方法的通用命名约定:
-
getInstance - 返回一个由参数描述的实例 […]
-
newInstance - 与 getInstance 类似,但它保证返回的每个实例都与其他实例不同。
-
newType - 与 newInstance 类似,但在工厂方法位于不同类中时使用。 Type 表示工厂方法返回的对象类型。
关于显式类型参数
在大多数情况下,您不必显式提供类型参数,因为 Java 泛型类型推断系统通常可以确定您需要什么。
然而,要提供显式类型参数,语法是将其放在之前方法名称(而不是之后)。下面是一个使用显式参数调用来自java.util.Collections 的泛型方法<T> List<T> emptyList() 的示例:
Collections.<String>emptyList();
// Collections.emptyList<String>(); // DOES NOT COMPILE
请注意,泛型方法调用的显式类型参数化的语法怪癖是您必须限定类型(如果 static)或您正在调用该方法的对象,甚至如果不是显式参数化,则可以省略它们。
参考文献
附录:来自 Guava 的集合工厂方法
需要注意的是Guava实际上已经为Java Collections Framework中的类型提供了static工厂方法:
来自主package com.google.common.collect:
其实本着Effective Java 2nd Edition推荐的精神,Guava自己的集合不提供public构造函数,而是提供static create()工厂方法:
库的其余部分还提供了许多非常有用的功能。