我认为您无法将Java泛型类型参数绑定(bind)到下限(即使用super
关键字)。我正在阅读Angelika Langer Generics FAQ had to say on the subject。他们说,这基本上可以归结为无用的下限(“没有任何意义”)。
我不相信。我可以想象它们的用途是帮助您更灵活地调用产生类型化结果的库方法的调用者。想象一下一个方法,该方法创建了用户指定大小的数组列表,并用空字符串填充了该列表。一个简单的声明是
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"));
最佳答案
基本上,它不够用。
我认为您的示例指出了下限的唯一优势,即FAQ称为Restricted Instantiation
的功能:
但是正如其他帖子所指出的那样,即使此功能的用处也可能受到限制。
由于多态性和特化的性质,如FAQ(访问非静态成员和清除类型)中所述,上限远比下限有用。我怀疑下限引入的复杂性不值得其有限的值(value)。
OP:我想补充一点,我想您确实表明它很有用,只是不够用。提出无可辩驳的杀手级用例,我将支持JSR。 :-)