为什么Java类型参数不能有下限?

Mar*_*ers 48 java generics bounds

我认为你不能将Java泛型类型参数绑定到下限(即使用super关键字).我正在阅读Angelika Langer Generics常见问题解答中有关该主题的内容.他们说这基本上归结为下限无用("没有任何意义").

我不相信.我可以想象它们的用途可以帮助您更灵活地生成类型化结果的库方法的调用者.想象一个方法,它创建一个用户指定大小的数组列表,并用空字符串填充它.一个简单的声明就是

public static ArrayList<String> createArrayListFullOfEmptyStrings(int i);
Run Code Online (Sandbox Code Playgroud)

但这对您的客户来说是不必要的限制.为什么他们不能像这样调用你的方法:

//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);
Run Code Online (Sandbox Code Playgroud)

在这一点上,我很想尝试以下定义:

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;
}
Run Code Online (Sandbox Code Playgroud)

但它不会编译; super在这种情况下,关键字是非法的.

上面我的例子是一个坏例子(忽略我在下面说的)?为什么这里没有下限?如果它有用,那么Java中不允许它的真正原因是什么?

PS

我知道一个更好的组织可能是这样的:

public static void populateListWithEmptyStrings(List<? super String> list, int size);

List<CharSequence> list = new ArrayList<CharSequence>();
populateListWithEmptyStrings(list, 5);
Run Code Online (Sandbox Code Playgroud)

我们为了这个问题的目的可以假装由于一个要求,我们需要在一个方法调用中做两个操作吗?

编辑

@Tom G(理所当然地)问有什么好处List<CharSequence>会超过a List<String>.首先,没有人说返回的列表是不可变的,所以这里有一个优点:

List<CharSequence> l2 = createArrayListFullOfEmptyStrings(5);
l2.add(new StringBuilder("foo").append("bar"));
Run Code Online (Sandbox Code Playgroud)

Ber*_*t F 15

基本上,它不够用.

我认为你的例子指出了下限的唯一优势,FAQ调用的一个功能Restricted Instantiation:

底线是:所有"超级" 界限会购买你的限制,只有超类型的数字可以用作类型参数.....

但正如其他帖子指出的那样,甚至这个功能的用处也是有限的.

由于多态性和特化的性质,上界比下界更有用,如FAQ(访问非静态成员类型擦除)所述.我怀疑下界引入的复杂性不值得其有限的价值.


OP:我想补充一下,我认为你确实表明它很有用,只是没用.想出无可辩驳的杀手级用例,我将支持JSR.:-)

  • 哈,我不在乎*那么多.我很好,这是一个成本效益的决定.我对FAQ的坚持认为他们"没有意义"感到沮丧.不幸的是,他们只检查该部分中类类型参数的场景,同时完全忽略方法类型参数. (4认同)
  • @Lil你是对的,但我没有误读常见问题解答 - 自从几年前我发布了答案以来,常见问题解答已经改变了(https://web.archive.org/web/20110707143151/http://www.angelikalanger.com/ GenericsFAQ/FAQSections/TypeParameters.html).常见问题改变为承认OP角落案件偶尔有用,我在最后一句中也承认了这一点.我可能会在将来更新答案,反映更新的常见问题和您的评论. (2认同)
  • 那个向下兼容到某一点的数据库管理器类呢?例如,您希望能够包含您的类型的超类,但创建新类型的元素.你可能需要这样的东西:`class DBManager <T extends foo,S super T> {...}`其中T表示数据类型的当前版本,S表示要包含在管理器中的旧版本.假设您通过扩展旧版本来构建新版本. (2认同)
  • 在每天肯定使用的类型层次结构中有一个流行的用例:`Collection <E> .toArray(T [])`.方法`toArray`的类型参数`T`应该表示`Collection`的类型参数`E`的超类型,但不能指定关系,因此`T`可以是任何东西,与`E`无关,编译器不会告诉你.这会影响*all*集合. (2认同)

irr*_*ble 11

例如,规范确实讨论了类型参数的下界

4.10.2

类型变量是其下限的直接超类型.

5.1.10

一个新的类型变量......其下限

似乎一个类型变量只有一个(非空)下界,如果它是通配符捕获的合成结果.如果语言允许所有类型参数的下限,该怎么办?可能它不会造成很多麻烦,并且它被排除在外只是为了保持泛型更简单(好......)更新据说,对有界类型参数的理论研究并未彻底进行.

更新:声称下限的论文没问题:丹尼尔史密斯的"Java类型推断是否破坏:我们可以修复它"

RETRACT:以下参数是错误的.OP的例子是合法的.

你的具体例子不是很有说服力.首先,它不是类型安全的.返回的列表确实是一个List<String>,将它视为另一种类型是不安全的.假设您的代码编译:

    List<CharSequence> l2 = createArrayListFullOfEmptyStrings(5);
Run Code Online (Sandbox Code Playgroud)

那么我们可以添加非String,这是错误的

    CharSequence chars = new StringBuilder();
    l2.add(chars); 
Run Code Online (Sandbox Code Playgroud)

好吧a 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());
Run Code Online (Sandbox Code Playgroud)

  • 感谢JLS refs.现在两点.**1)**将`createArray ...`的结果赋值给`List <CharSequence>`(如果支持下界)则不是类型不安全的.它从来不是一个`List <String>`; 它将是一个`List <CharSequence>`"来自创造"(虽然有擦除这是一个奇怪的事情).它从未被视为`List <String>`.继续向它添加一个StringBuilder实例绝不是不安全的.**2)**将结果分配给`List <?扩展CharSequence>`完全没有使用`List <String>`的好处; 它实际上更具限制性. (3认同)
  • 你是对的,你的榜样是有效的.不包括下限可能是因为它没有很好地研究.这不是一件简单的事情,必须有理论上的支持.例如,请参阅JLS3 15.12.2.7,并注意它有多复杂.它非常复杂,java编译器有很多与之相关的bug.现在假设我们添加下限.不仅算法会多次膨胀,而且我们甚至不知道它是否是一种合理的算法. (2认同)
  • JLS提到的论文,Java Generics基于:http://www.sato.kuis.kyoto-u.ac.jp/~igarashi/papers/variance.html (2认同)