栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 面试经验 > 面试问答

Java泛型-使泛型扩展2个接口

面试问答 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

Java泛型-使泛型扩展2个接口

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>

假设调用方未明确指定

T
and
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指出了这一点)。



转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/573705.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号