Effective Java(3rd)-Item30 优先使用泛
不仅是类可以被泛化,方法也可以。静态工具方法上的参数化类型通常是泛型。所有Collections(比如binarySearch和sort)“算法”方法都是泛型。
编写泛型方法与编写泛型类型相似。考虑这个有缺点的方法,它返回了两个set的合集:
image.png
这个方法编译成功了,但是会有两个警告:
image.png
要修复这些警告并使方法类型安全,修改其声明以声明一个类型参数,便是三个set的元素类型(两个参数和返回值),并在整个方法中使用此类型参数。声明类型参数的类型参数列表介于方法的修饰符和返回类型之间。在这个例子中,类型参数列表是<E>,返回类型是Set<E>。类型参数的命名约定对于泛型方法和泛型类型是相同的(item29)
image.png至少对于简单的泛型方法来说,这就是全部。此方法编译时不发生任何警告,并提供类型安全性以及易使用。这里有一个简单的程序来练习这个方法。这个程序不包含错误或警告的强制转换和编译:
image.png
当你运行这个程序的时候,它会打印 [Moe, Tom, Harry, Larry, Curly, Dick]。(输出的元素的顺序取决于实现)。
union方法的一个限制是,所有三个集合(两个输入参数和返回值)的类型必须完全相同。你可以使用有界通配符类型(item31 ),使方法更加灵活。
有时,你需要创建一个不可变但适用于许多不同类型的对象。由于泛型是通过擦除( item28)实现得,所以可以使用单个对象进行所有必需得类型参数化,但需要编写一个静态工厂方法来重复为每个请求的类型参数化分配对象。该模式称为泛型单例工厂,用于函数对象( item42 ),如Collections.reverseOrder,以及Collections.emptySet。
假设你想要编写一个标识函数分发器。标准库提供了Function.identity,所以没有理由写你自己的(item51 )。但这是由教育意义的。创建一个新的标识函数对象是浪费时间的,因为它是无状态的。如果Java的泛型被具体化了,那么每种类型都需要一个标识函数,但是他们被擦除了,一个泛型的单例就足够了。如下是它的外观:
IDENTITY_FN强制转换(UnaryFunction<T>)会生成一个未经检查的强制转换警告,因为UnaryOperator<Object>不是每个T都能转换的。但是恒等函数是特殊的:它不加修改地返回了它的参数,所以我们知道,无论T的值是什么,它都是一个UnaryOperator<T>.所以,我们可以自信地抑制该强制转换生成的未经检查的强制转换警告。一旦我们这样坐,代码编译就不会有错误或警告。
下面是一个示例程序,使用泛型单例作为UnaryOperator<String>和UnaryOperator<Number>。与往常一样,它编译时没有错误或警告:
image.png
允许类型参数被包含该类型参数本身的某个表达式所限制,虽然相对较少。这就是所谓的递归类型绑定。递归类型界的一种常见用法是与可比较的接口相关联,该接受定义了类型的自然排序。( item14)。这里显示了该接口:
image.png 类型参数T定义实现类型的元素的类型Comparable<T>可被比较。实际上,几乎所有类型都只能与它们自己类型的元素进行比较。因此,例如,String实现了Comparable<String>,Integer实现了Comparable<Integer>,等等。
许多方法采用实现类似排序的元素集合,计算其最小或最大值,等等。要做到这些,要求集合中的每个元素都可以与其中的每个其他元素进行比较,换句话说,列表中的元素必须是可以相互比较的。下面是如何表示该约束:
类型界<E extends Comparable<E>>可以被读作”任何类型E可以被它自己比较“,它或多或少符合相互可比性的概念。
下面是一个与前一个声明一起使用的方法。它根据元素的自然顺序计算集合中的最大值,并且编译时没有错误或警告:
image.png
注意到如果这个list是空的,会抛出IllegalArgumentException。一个更好的替代方法是返回Optional<E>(item55 ).
递归类型界可以变得更灵活,但是幸运的是,他们很少这么做。如果你理解这个术语,它的通配符变体(item31) ,以及自模拟的术语(item2),你能够处理实践中遇到的大多数递归类型界。
总之,泛型 方法和泛型类型一样,比要求客户端对输入参数和返回值进行显示转换的方法更安全,更容易使用。和类型一样,你应该确保不用强制转换就可以使用你的方法,这通常意味着它们是通用的。和类型一样,你应该泛化使用需要强制转换的现有方法。这使新使用者更好的不破坏已存在的客户端(item26 )
本文写于2019.6.27,历时1天