Reimeus已经指出,您在编辑中要求的内容是不可能的。我只想扩展一下原因。
人们会认为您可以使用以下内容:
public <T, U extends T & IDisposable> void mapThis( Class<? extends MyClass<T>> key, Class<? extends U> value) { ... }实际上,这就是我第一次看到这篇文章时想到的。但这实际上会导致编译器错误:
类型变量不能跟其他界限
为了帮助我解释原因,我想引用Victor Rudometov在OracleBlogs上发表的有关此错误的文章:
这个事实并不总是很清楚,但确实如此。以下代码不应编译:
interface I {}class TestBounds <U, T extends U & I> {}因为JLS第4章类型,值和变量部分4.4类型变量规定:“ 结合的由 任一 类型变量,或者可能接着进一步接口类型的类或接口类型T I
1,…,I Ñ。 ” 。因此,可以使用 T扩展U,T扩展SomeClass&I ,但不可以 T扩展U&I
。该规则适用于所有情况,包括类型变量以及方法和构造函数中的界限。
总而言之,施加此限制是为了“避免某些尴尬的情况出现”(JLS§4.9)。
什么样的尴尬情况?克里斯·波维尔克(ChrisPovirk)的回答描述了一个:
[限制的原因是]指定非法类型的可能性。具体而言,使用不同的参数两次扩展通用接口。我无法提出一个非人为的示例,但是:
class StringComparatorHolder> {
private final C comparator;
// …
}void foo(StringComparatorHolder<Comparator<Integer>, ?> holder) { ... }现在
holder.comparator是Comparator<Integer>和Comparator<String>。
克里斯还指出了Sun bug4899305,它是与该语言限制相抗衡的bug。由于无法修复,已关闭,并带有以下注释:
如果类型变量后面可以跟着类型变量或(可能是参数化的)接口,则可能会有更多相互递归的类型变量,这很难处理。当边界仅仅是参数化类型(例如)时,事情已经很复杂
<S,RextendsComparable<S>>。因此,界限现在不会改变。javac和Eclipse都同意S&T并且S&Comparable<S>是非法的。
因此,这就是限制的背后原因。我要特别指出泛型方法(您的问题所涉及的问题),我还要进一步指出,类型推断理论上将导致此类界限毫无意义。
如果我们重新检查以上假设签名中声明的类型参数:
<T, U extends T & IDisposable>
假设调用方未明确指定
Tand
U,则可以将其简化为以下内容:
<T, U extends Object & IDisposable>
或者只是这个(细微的差别,但这是另一个主题):
<T, U extends IDisposable>
这是因为
T没有界限,所以无论传入哪种类型的参数,
T都
Object至少可以始终解析为,然后可以
U。
让我们回去说
T有界:
<T extends Foo, U extends T & IDisposable>
可以用相同的方式减少它(
Foo可以是类或接口):
<T extends Foo, U extends Foo & IDisposable>
基于这种推理,就将调用方限制为更特定的参数而言,您要尝试实现的语法毫无意义。
Java 8之前的附录:
在此之前的Java 8, 是 一个用例你想做什么。由于编译器如何推断通用方法类型参数的限制,我的上述推理是不合时宜的。采用以下通用方法:
class MyClass { static <T> void foo(T t1, T t2) { }}这是尝试制作一个采用两个“相同类型”参数的方法的常见初学者错误。当然,由于继承的方式,这毫无意义:
MyClass.foo("asdf", 42); // legal在这里,
T可以推断为
Object-这与简化
mapThis类型参数的早期推理相吻合。您必须手动指定类型参数才能实现预期的类型检查:
MyClass.<String>foo("asdf", 42); // compiler error但是, 这是您的用例开始出现的地方,带有交错边界的多个类型参数是另一回事:
class MyClass { static <T, U extends T> void foo(T t, U u) { }}现在,此调用错误:
MyClass.foo("asdf", 42); // compiler error表已经翻转了-我们必须手动放松类型参数才能进行编译:
MyClass.<Object, Object>foo("asdf", 42); // legal发生这种情况是因为编译器推断方法类型参数的方式有限。因此,您想要实现的目标实际上是在限制调用者参数的应用程序。
但是,此问题似乎已在Java 8中得到修复,
MyClass.foo("asdf",42)现在可以编译而没有任何错误(感谢Regent指出了这一点)。


