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

我认为您不能将Java泛型类型参数绑定到下限(即使用super关键字)。我正在阅读Angelika Langer泛型常见问题解答对此主题的看法。他们说,这基本上可以归结为无用的下限(“没有任何意义”)。


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


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(合理地)询问a相List<CharSequence>对于a有什么好处List<String>。首先,没有人说返回的列表是不可变的,所以这是一个优点:


List<CharSequence> l2 = createArrayListFullOfEmptyStrings(5);

l2.add(new StringBuilder("foo").append("bar"));


饮歌长啸
浏览 455回答 3
3回答

白衣非少年

基本上,它不够有用。我认为您的示例指出了下限的唯一优势,即FAQ所称的功能Restricted Instantiation:底线是:“超级” 绑定将为您提供的所有限制是,只有Number的超类型可以用作类型实参。....但是,正如其他帖子所指出的那样,即使此功能的实用性也可能受到限制。由于多态性和专业化的性质,如FAQ(访问非静态成员和清除类型)所述,上限比下限有用得多。我怀疑下限引入的复杂性不值得其有限的价值。OP:我想补充一点,我想您确实表明它很有用,只是不够用。提出毫无疑问的杀手级用例,我将支持JSR。:-)

守着一只汪

规范确实谈到了类型参数的下限,例如4.10.2类型变量是其下限的直接超类型。5.1.10一个新鲜的类型变量...其下界看起来,如果类型变量是通配符捕获的合成变量,则它只有一个(非空)下限。如果语言允许所有类型参数的下限怎么办?可能不会引起很多麻烦,并且仅是为了使泛型更简单而已被排除在外(好吧……)。更新:据说对下界类型参数的理论研究尚未彻底进行。更新:一篇声称下限的论文是可以的:Daniel Smith撰写的“ Java类型推理被打破:我们可以解决它”RETRACT:以下参数是错误的。OP的示例是合法的。您的特定示例不是很令人信服。首先,它不是类型安全的。返回的列表确实是List<String>,将其视为另一种类型是不安全的。假设您的代码可以编译:&nbsp; &nbsp; List<CharSequence> l2 = createArrayListFullOfEmptyStrings(5);然后我们可以向其添加非字符串,这是错误的&nbsp; &nbsp; CharSequence chars = new StringBuilder();&nbsp; &nbsp; l2.add(chars);&nbsp;好吧List<String>不是,但有点像CharSequence的列表。使用通配符可以解决您的需求:public static&nbsp; List<String> createArrayListFullOfEmptyStrings(int size)&nbsp;&nbsp;// a list of some specific subtype of CharSequence&nbsp;List<? extends CharSequence> l2 = createArrayListFullOfEmptyStrings(5);// legal. can retrieve elements as CharSequenceCharSequence chars = l2.get(0);// illegal, won't compile. cannot insert elements as CharSequencel2.add(new StringBuilder());

繁花如伊

这不仅仅是一个答案,这是另一个(可能是杀手??)用例。我有一个ModelDecorator助手。我希望它具有以下公共APIclass ModelDecorator<T>{&nbsp; &nbsp; public static <T> ModelDecorator<T> create(Class<T> clazz);&nbsp; &nbsp; 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不从C继承。显然,如果可以的话:&nbsp; &nbsp; public <SUPER super T> T from(SUPER fromInstance);那会解决我的问题。
打开App,查看更多内容
随时随地看视频慕课网APP

相关分类

Java