为什么我应该优先使用通配符来键入参数?

时间:2016-05-04 23:58:59

标签: java generics wildcard

我正在阅读Effective Java 2nd Edition,在Item 28: Use bounded wildcards to increase API flexibility中有以下内容:

// Two possible declarations for the swap method

public static <E> void swap(List<E> list, int i, int j);
public static void swap(List<?> list, int i, int j);
     

这两个声明中的哪一个更可取,为什么?在公共场合   API,第二个更好,因为它更简单。你传入一个列表 - 任何   list-和方法交换索引元素。没有类型   担心的参数。通常,如果仅显示类型参数   在方法声明中,将其替换为通配符。

我使用unbounded类型参数测试它,我没有看到任何缺点,我可以传递任何列表,我没有类型参数的问题,实际上无界的类型参数更好,因为我不需要帮手方法解释顺序:

  

有一种方法可以实现此方法,而无需使用不安全的方法   演员或原始类型。我们的想法是编写一个私有帮助方法   捕获通配符类型。辅助方法必须是通用方法   为了捕捉类型。这是它的外观:

public static void swap(List<?> list, int i, int j) {
    swapHelper(list, i, j);
}
// Private helper method for wildcard capture
private static <E> void swapHelper(List<E> list, int i, int j) {
    list.set(i, list.set(j, list.get(i)));
}

最后,这是我使用类型参数的实现:

 public static <E> void swap(List<E> list, int i, int j) {
        list.set(i, list.set(j, list.get(i)));
  }

和用法:

List<Object> integers = (...)
swap(integers, 1,2);

那么,为什么我要使用通配符呢?

问题是:为什么第二种方式更简单?我看不出原因!我想念一些细节?我真的很想了解布洛赫的意思。

1 个答案:

答案 0 :(得分:2)

首先,要了解布洛赫在这里提出关于偏好的声明 - 你不一定要同意他(我在这一点上目睹了长时间和艰苦的讨论,所以你不是唯一的一个。)

然而,他确实说明了为什么他认为这更好。我会尝试提出他的关键点,以便他们更清楚。

  

在公共API中,第二个更好,因为...没有类型参数需要担心。通常,如果类型参数在方法声明中只出现一次,请将其替换为通配符....

     

这个稍微复杂的实现......允许我们导出漂亮的基于通配符的声明....

     

在API中使用通配符类型虽然棘手,但却使API变得更加灵活。

换句话说,Bloch认为需要E类型是一个您不应向客户公开的实现细节 - swap()方法适用于任何List方法因此?是&#34;正确&#34;并且公开E绝不会使用户受益。从某种意义上说,这是项目52的概括:通过接口引用对象

请特别注意,此建议仅针对公共API。没有必要只在你打电话的代码中实现这种解决方法。

这个例子也可以说是人为的 - 两个解决方案之间并没有太大的区别,但希望你能想象出更复杂的方法需要通用类型作为其实现的一部分,而不是它们的公共签名。布洛赫的一般观点是,当用户不需要了解泛型类型时,即使这样做看起来微不足道,也不需要将这些知识强加给他们。