为什么Javatypes的参数不能有一个下界?
我收集你不能将Javagenericstypes参数绑定到下限(即使用super关键字)。 我正在阅读Angelika Langer Generics常见问题解答在这个问题上所说的话 。 他们说基本上归结为一个无用的下界(“没有任何意义”)。 
我不相信。 我可以想象他们的使用,以帮助您更灵活的图书馆方法,产生一个打字结果的调用者。 想象一下,创build一个用户指定大小的数组列表并填充空string的方法。 一个简单的声明将是
 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中不允许的真正原因是什么?
PS
我知道一个更好的组织可能是这样的:
 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 : 
底线是:所有“超级”的限制会买你的限制 ,只有超types的数字可以用作types参数 。 ….
但正如其他post所指出的,甚至这个function的用处也是有限的。
由于多态性和专业化的性质,如常见问题解答( 访问非静态成员和types擦除 )所述,上限比下限要有用得多。 我怀疑下界引入的复杂性是不值得的。
OP:我想补充我觉得你确实显示它是有用的,只是没有足够的用处。 拿出无可辩驳的杀手用例,我将支持JSR。 🙂
例如,规范确实讨论了types参数的下限
4.10.2
typesvariables是其下限的直接超types。
5.1.10
一个新的typesvariables…的下限
看起来,如果一个typesvariables是通配符捕获的合成结果,那么它只有一个(非空)下限。 如果语言允许所有types参数的下限呢? 可能不会造成很大的麻烦,只是为了保持generics的简单性而被排除在外(好吧…) 更新据说对低有界types参数的理论研究还没有彻底进行。
更新:声明下限的文章是可以的:“Javatypes的干扰:我们可以修复”Daniel Smith
RETRACT:以下参数是错误的。 OP的例子是合法的。
 你特别的例子不是很有说服力。 首先它不是安全的。 返回的列表确实是一个List<String> ,将其视为另一个types是不安全的。 假设你的代码编译: 
  List<CharSequence> l2 = createArrayListFullOfEmptyStrings(5); 
那么我们可以添加非string,这是错误的
  CharSequence chars = new StringBuilder(); l2.add(chars); 
 那么List<String>不是,但有点像CharSequence的列表。 您的需求可以通过使用通配符来解决: 
 public static List<String> createArrayListFullOfEmptyStrings(int size) // a list of some specific subtype of CharSequence List<? extends CharSequence> l2 = createArrayListFullOfEmptyStrings(5); // legal. can retrieve elements as CharSequence CharSequence chars = l2.get(0); // illegal, won't compile. cannot insert elements as CharSequence l2.add(new StringBuilder()); 
input列表给你什么好处呢? 当你遍历返回的集合时,你仍然应该能够执行以下操作:
 for(String s : returnedList) { CharSequence cs = s; //do something with your CharSequence } 
不止一个答案,这是另一个(可能是杀手?)的用例。 我有一个ModelDecorator帮手。 我希望它有以下的公共API
 class ModelDecorator<T>{ public static <T> ModelDecorator<T> create(Class<T> clazz); public <SUPER> T from(SUPER fromInstance); } 
所以,给定类A,B扩展A,可以这样使用:
 A a = new A(); B b = ModelDecorator.create(B.class).from(a); 
但是我想在T和SUPER上有界限,所以我确保只有子类可以使用API实例化。 在这一刻,我可以做到:
 C c = new C(); B b = ModelDecorator.create(B.class).from(c); 
B不从Cinheritance
显然,如果我可以这样做:
  public <SUPER super T> T from(SUPER fromInstance); 
这将解决我的问题。
嗯,好的 – 让我们来看看这个。 你定义一个方法:
 public static <T super String> List<T> createArrayListFullOfEmptyStrings(int size) { 
这意味着什么? 这意味着,如果我打电话给你的方法,那么我得到一个string的超类列表。 也许它返回一个String列表。 也许它返回一个Object列表。 我不知道。
凉。
 List<Object> l1 = createArrayListFullOfEmptyStrings(5); 
 据你说,这应该编译。 但是这是不对的! 我可以把一个Integer放到Object  – l1.add(3)的列表中。 但是,如果你正在返回一个String列表,那么这样做应该是非法的。 
 List<String> l3 = createArrayListFullOfEmptyStrings(5); 
 据你说,这应该编译。 但是这是不对的!  l3.get(1)应该总是返回一个string…但是该方法可能已经返回了一个Object列表,这意味着l3.get(1)可以想象为一个Integer。 
唯一的作品是
 List<? super String> l5 = createArrayListFullOfEmptyStrings(5); 
 我所知道的是,我可以安全地调用l4.put("foo") ,并且我可以安全地获得Object o = l4.get(2) 。