[英]Java generics - purpose of wildcard except for lower bounds?
使用通配符进行无界或上限泛型的目的是什么? 进一步来说:
为什么我会说public static void foo(List<?> bar)
而不是public static <E> void foo(List<E> bar)
?
为什么我会说public static void foo(List<? extends Baz> bar)
而不是public static <E extends Baz> void foo(List<E> bar)
?
如果您不打算在后面的代码中引用E
,则无需声明它。
减少程序员的内存压力。
如果在运行时决定列表的类型,则需要使用通配符。
如果使用任何命令行参数运行,以下程序将打印List<String>
; 否则会打印List<Number>
:
public class Test {
public static List<String> listOfStrings = Arrays.asList("hello", "world");
public static List<Number> listOfNumbers = Arrays.asList(1, 2, 3, 4.5);
public static List<?> getListOfUnknown(boolean arg) {
if(arg) return listOfStrings;
else return listOfNumbers;
}
public static void main(String[] args) {
System.out.println(getListOfUnknown(args.length > 0));
}
}
带通配符的版本是首选。 如果参数的类型为List<?>
,则很明显将接受任何List
。 如果接受任何List
,则没有理由给type参数一个名称,因此写<E>
只会是混乱的。 另一方面,如果类型参数在签名中出现两次,则无法使用通配符。 例如,此签名需要一个类型参数。
public static <E> List<E> combineLists(List<E> list1, List<E> list2)
实际上在那个例子中,如果参数类型为List<? extends E>
List<? extends E>
(没有通配符的唯一方法就是有三个类型参数,一个混乱)。
在Effective Java中,建议即使方法体中需要type参数,也应该更喜欢带有通配符的签名版本,并编写一个私有帮助方法来实现这一点。 例如:
public static void swapFirstAndLast(List<?> list) {
helper(list);
}
private static <E> void helper(List<E> list) {
int size = list.size();
E e = list.get(0);
list.set(0, list.get(size - 1)); // These lines would not be possible
list.set(size - 1, e); // If the type of list were List<?>
}
泛型方法的官方教程已经解释得很好。
...类型参数T仅使用一次。 返回类型不依赖于类型参数,也不依赖于方法的任何其他参数(在这种情况下,只有一个参数)。 这告诉我们类型参数用于多态; 它唯一的作用是允许在不同的调用站点使用各种实际的参数类型。 如果是这种情况,则应使用通配符。 ...
通用方法允许使用类型参数来表示方法和/或其返回类型的一个或多个参数的类型之间的依赖关系。 如果没有这种依赖关系,则不应使用通用方法。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.