但我并不认同。我可以想象一个用途,它可以帮助您更加灵活地响应库方法调用者的需求,并生成一个类型化的结果。想象一下一个方法,它创建一个用户指定大小的数组列表,并用空字符串填充它。一个简单的声明可能是:
public static ArrayList<String> createArrayListFullOfEmptyStrings(int i);
但这对你的客户来说是不必要的限制。为什么他们不能像这样调用你的方法:
//should compile
List<Object> l1 = createArrayListFullOfEmptyStrings(5);
List<CharSequence> l2 = createArrayListFullOfEmptyStrings(5);
List<String> l3 = createArrayListFullOfEmptyStrings(5);
//shouldn't compile
List<Integer> l4 = createArrayListFullOfEmptyStrings(5);
此时我会尝试以下定义:
public static <T super String> List<T> createArrayListFullOfEmptyStrings(int size) {
List<T> list = new ArrayList<T>(size);
for(int i = 0; i < size; i++) {
list.add("");
}
return list;
}
但它将无法编译; 在此上下文中,super
关键字是非法的。
忽略我下面说的内容,上面的例子是否不好?为什么在这里使用下限没有用?如果有用,那么它不被允许在Java中的真正原因是什么?
附言
我知道更好的组织方式可能是这样的:
public static void populateListWithEmptyStrings(List<? super String> list, int size);
List<CharSequence> list = new ArrayList<CharSequence>();
populateListWithEmptyStrings(list, 5);
为了回答这个问题,我们可以假设由于某种要求,我们需要在一个方法调用中执行两个操作吗?
编辑
@Tom G(有理由地)询问拥有List<CharSequence>
相比于List<String>
有何优势。首先,没有人说返回的列表是不可变的,因此这里有一个优点:
List<CharSequence> l2 = createArrayListFullOfEmptyStrings(5);
l2.add(new StringBuilder("foo").append("bar"));
Collection.toArray(T[])
方法可以使用下限来实现合法的用法。通过将类型变量从<T>
更改为<T super E>
,可以防止该方法出现ArrayStoreException
异常。 - JeffreytoArray
在任何情况下都不与集合的元素类型相关联。 - Mark Peters super List> C internIfEmpty(C collection) {
return collection.isEmpty() ? Collections.emptyList() : collection;
}
- shmosel<T> Collection<T> internIfEmpty(Collection<T>)
,另一个是<T> List<T> internIfEmpty(List<T>)
。编译器会为您调用更具体的方法,您只需让第一个返回第二个的结果即可。 - Mark Peters