为什么我不能在带有多个边界的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和限制的更多讨论。
两个可能的原因是:
-
复杂。 Sun bug 4899305表明,包含types参数和其他参数化types的边界将允许比已经存在的更复杂的相互recursiontypes。 总之, 布鲁诺的答案 。
-
指定非法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参数作为绑定,则不能使用任何其他绑定,就像错误消息所述。
为什么限制? 我不知道。