为什么我不能在带有多个边界的types参数中使用types参数?

所以,我明白以下不起作用,但为什么不起作用?

interface Adapter<E> {} class Adaptulator<I> { <E, A extends I & Adapter<E>> void add(Class<E> extl, Class<A> intl) { addAdapterFactory(new AdapterFactory<E, A>(extl, intl)); } } 

add()方法给我一个编译错误,“当第一次绑定是一个types参数”(在Eclipse中)或“types参数不能跟在其他边界之后”(在IDEA中)时,不能指定任何附加绑定的Adapter <E>拿你的select。

显然你只是不允许在&之前使用types参数I ,那就是。 (而且在你问之前,如果你换了他们,这是行不通的,因为I不能保证I不是一个具体的类。)但是为什么不呢? 我已经浏览了Angelika Langer的常见问题解答并找不到答案。

一般来说,当一些generics限制看起来是任意的,这是因为你已经创build了一个types系统实际上不能实现正确性的情况。 但我不明白什么情况会打破我在这里要做的事情。 我想说也许它与types擦除后方法调度有关,但只有一个add()方法,所以它不像有任何含糊不清…

有人能certificate我的问题吗?

我也不确定为什么限制在那里。 您可以尝试发送一封友好的电子邮件给Java 5 Generics(主要是Gilad Bracha和Neal Gafter)的devise师。

我的猜测是,他们只想支持绝对最小的交集types (这就是多重​​边界本质上是什么),使语言不会比所需的复杂。 交集不能用作types注释; 一个程序员只能expression一个交点,当它出现在一个typesvariables的上界时。

为什么这个案例甚至得到支持? 答案是多重边界允许您控制擦除,这可以在生成现有类时保持二进制兼容性。 如Naftalin和Wadler的书中第17.4节所解释的, max方法在逻辑上具有以下签名:

 public static <T extends Comparable<? super T>> T max(Collection<? extends T> coll) 

但是,这消除了:

 public static Comparable max(Collection coll) 

这与max的历史签名不匹配,并导致旧客户端中断。 有多个边界时,只有最左边的边界被考虑用于擦除,所以如果max给出以下签名:

 public static <T extends Object & Comparable<? super T>> T max(Collection<? extends T> coll) 

然后删除它的签名变成:

 public static Object max(Collection coll) 

这与generics之前的max签名相同。

Javadevise者只关心这个简单的例子,并限制其他(更高级的)交集types的使用似乎是合理的,因为他们只是不确定它可能带来的复杂性。 所以这个devise决定的原因不需要是一个可能的安全问题(如问题所示)。

关于即将出版的OOPSLA论文中有关generics的交叉types和限制的更多讨论。

两个可能的原因是:

  1. 复杂。 Sun bug 4899305表明,包含types参数和其他参数化types的边界将允许比已经存在的更复杂的相互recursiontypes。 总之, 布鲁诺的答案 。

  2. 指定非法types的可能性。 具体来说, 用不同的参数扩展一个通用接口两次 。 我不能拿出一个没有人为的例子,但是:

      / **包含一个比较器<String>,它也实现给定typesT. * /
     class StringComparatorHolder <T,C扩展T&Comparator <String >> {
    专用的最终C比较器;
     // ...
     }
    
     void foo(StringComparatorHolder <Comparator <Integer>,?>持有者){...} 

现在, holder.comparator是一个Comparator<Integer>和一个Comparator<String> 。 我不清楚这会给编译器带来多大的麻烦,但显然不好。 特别是假设Comparator有这样一个方法:

 无效sorting(List <?extends T> list); 

我们的Comparator<Integer> / Comparator<String>混合现在有两个方法相同的擦除:

 无效sorting(List <?extends Integer> list);
 void sort(List <?extends String> list); 

这是由于这些原因,你不能直接指定这种types:

  <T扩展Comparator <Integer>&Comparator <String >> void bar(){...} 
  java.util.Comparator不能被不同的参数inheritance:
     <java.lang.Integer>和<java.lang.String> 

由于<A extends I & Adapter<E>>允许你间接地做同样的事情,所以也是一样的。

这是JLS的另一个引用:

绑定的forms是受限的(只有第一个元素可能是一个类或typesvariables,并且只有一个typesvariables可能出现在边界中),以防止某些尴尬的情况出现

这些尴尬的情况到底是什么,我不知道。

这可能不是回答根本问题,但只是要指出,规范明确禁止它。 谷歌search的错误消息把我带到了这个博客条目 ,这进一步指向了jls 4.4 :

边界由一个typesvariables或者一个类或接口typesT组成,可能跟着更多接口typesI1,…,In。

因此,如果使用types参数作为绑定,则不能使用任何其他绑定,就像错误消息所述。

为什么限制? 我不知道。