第27条 泛型——优先考虑泛型方法

来源:互联网 发布:高大上的礼物知乎 编辑:程序博客网 时间:2024/06/07 06:22

转自:http://blog.csdn.net/u014723123/article/details/38016957

术语:

 递归类型限制:通过某个包含该类型参数本身的表达式来限制类型参数。


        考虑如下的方法,它的作用是返回两个集合的联合:

[java] view plain copy
  1. // Users raw types - unaccepable!  
  2. public static Set union(Set s1, Set s2) {  
  3.     Set result = new HashSet(s1);  
  4.     result.addAll(s2);  
  5.     return result;  
  6. }  
        虽然这个方法可以编译,但是编译这段代码会产生警告,为了修正这些警告(在新代码中不应该直接使用原始类型,当前是为了举例子)要将方法声名修改为声明一个类型参数,表示这三个元素类型(两个参数及一个返回值),并在方法中使用类型参数。声名类型参数的类型参数列表,处在方法的修饰符及其返回类型之间,修改后的代码如下:
[java] view plain copy
  1. // Generic method  
  2. public static <E> Set<E> union(Set<E> s1, Set<E> s2) {  
  3.     Set<E> result = new HashSet<E>(s1);  
  4.     result.addAll(s2);  
  5.     return result;  
  6. }  
        当前这个版本的union方法即为一般的泛型方法,但是它有一个限制,要求三个集合的类型(两个输入参数及一个返回值)必须全部相同。利用有限制的通配符类型可以使这个方法变得更加灵活。

        泛型方法的一个显著特征是,无需明确指定类型参数的值,不像调用泛型构造器的时候是必须要指定类型参数的,在为泛型方法的类型会存在一个类型推导的过程。编译器通过检查方法参数的类型来计算类型的值。在调用 泛型构造器的时候,要明确传递类型参数的值可能有点麻烦。类型参数出现在了变量的声明的左右两边,显得冗余:

[java] view plain copy
  1. // Parameterized type instance creation with constructor  
  2. Map<String, List<String>> anagrams =   
  3.                  new HashMap<String, List<String>>();  
        对于这情况 ,可以遵照第一条,提供一个静态工厂方法来简化:

[java] view plain copy
  1. // Generic static factory method  
  2. public static <K, V> HashMap<K, V> newHashMap() {  
  3.     return new HashMap<K, V>();  
  4. }  
        利用上面的静态工厂方法,我们可以把变量声明右侧的参数类型省略掉,当参数类型多而复杂时尤其有效。

        有时会需要创建不可变但是又适合于许多不同类型的对象,由于泛型是通过擦除来实现的,可以给所有的必要的类型参数使用同一个单个对象,但是需要一个静态的工厂方法来给每个必要的类型参数分发对象。这种模式叫做“泛型单例工厂”,这种模式最常用于函数的对象。假设有一个接口,描述了一个方法,该方法接受和返回某个类型T的值:

[java] view plain copy
  1. public interface UnaryFunction<T> {  
  2.     T apply(T arg);  
  3. }  
        现在假设要提供一个恒等函数,如果 在每次需要的时候都重新创建一个这样会很浪费,因为它是无状态的。如果泛型被具体化,那么每个类型都必须持有相应类型的桓等函数,但是在运行时擦除类型信息后,它们并没有什么区别,所以在这种情况下,只需要一个泛型单例就够了。请看以下示例:

[java] view plain copy
  1. // Generic singleton factory pattern  
  2. private static UnaryFunction<Object> INDENTITY_FUNCTION =  
  3.      new UnaryFunction<Object> {  
  4.          public Object apply(Object arg) { return arg; }  
  5.      };  
  6.        
  7. // IDENTITY_FUNCTION is stateless and its type parameter is  
  8. // unbounded so it's safe to share one instance across all types.  
  9. @SuppressWarnings("unchecked")  
  10. public static <T> UnaryFunction<T> indentityFunction() {  
  11.     return (UnaryFunction<T>)INDENTITY_FUNCTION;  
  12. }  
        递归类型限制最普遍的用途与Comparable接口有关,它定义类型的自然顺序。许多方法都带有一个实现Comparable接口的元素列表,为了对列表进行排序,并在其中进行搜索,计算出它的最小值或者最大值等等。要完成这其中的任何一项工作要求列表中的每个元素都能够与列表中的其他元素相比较,下面是如何表达这种约束条件的一个示例:

[java] view plain copy
  1. // Using a recursive type bound to express mutual comparability  
  2. public static <T extends Comparable<T>> T max(List<T> list) {  
  3.     ...  
  4. }  
        上面的声名要求T是可以与自身同类型对象相比较的类型,extends可以解释为"实现某功能"。

        总之,泛型方法就像泛型一样,使用起来比要求客户端转换输入参数并返回值的方法来的更加安全,也更加容易。就像类型一样,你应该确保新的方法可以不用转换就能使用,这通常意味着要将它们泛型化。并且就像类型一样,还应该将现有的方法泛型化,使新用户使用起来更加轻松,且不会破坏现有的客户端。

0 0
原创粉丝点击