通用返回类型上限 – 接口与类 – 令人惊讶的有效代码

问题:

 This is a real-world example from a 3rd party library API, but simplified.
 Compiled with Oracle JDK 8u72
考虑这两种方法:

<X extends CharSequence> X getCharSequence() {
    return (X) "hello";
}

<X extends String> X getString() {
    return (X) "hello";
}

两者都报告一个“未经检查的投票”警告 – 我得到了为什么。令我困惑的是我为什么打电话

Integer x = getCharSequence();

它编译?编译器应该知道Integer不实现CharSequence。打电话给

Integer y = getString();

给出错误(如预期)

有人可以解释为什么这种行为被认为是有效的?怎么会有用?
客户端不知道这个电话是不安全的 – 客户端的代码编译没有警告。为什么编译器不会警告/发出错误?
另外,它与这个例子有什么不同呢?

<X extends CharSequence> void doCharSequence(List<X> l) {
}

List<CharSequence> chsL = new ArrayList<>();
doCharSequence(chsL); // compiles

List<Integer> intL = new ArrayList<>();
doCharSequence(intL); // error

试图通过List<Integer>给出一个错误,如预期的:

如果报告为错误,为什么Integer x = getCharSequence();不是?

回答:

 CharSequenceinterface。因此,即使SomeClass不实现CharSequence,完全可以创建一个类

class SubClass extends SomeClass implements CharSequence

所以你可以写

SomeClass c = getCharSequence();

因为推断的类型X是交集类型SomeClass & CharSequence
Integer的情况下,这是有点奇怪,因为Integer是最终的,但final在这些规则中没有任何作用。例如你可以写

<T extends Integer &amp; CharSequence>

另一方面,String不是interface,所以不可能扩展SomeClass获取String的子类型,因为java不支持类的多重继承。
使用List的例子,你需要记住泛型不是协变的,也不是逆转的。这意味着如果XY的子类型,List<X>既不是子类型也不是超类型List<Y>。由于Integer不实施CharSequence,您不能在doCharSequence方法中使用List<Integer>
但是,您可以将其编译

<T extends Integer &amp; CharSequence> void foo(List<T> list) {
    doCharSequence(list);
}  

如果你有这样一种returns一个List<T>的方法:

static <T extends CharSequence> List<T> foo() 

你可以做

List<? extends Integer> list = foo();

再次,这是因为推断的类型是Integer & CharSequence,这是Integer的子类型
当指定多个边界(例如<T extends SomeClass & CharSequence>)时,交集类型会隐式发生。
有关更多信息,here是JLS的一部分,它解释了类型边界的工作原理。您可以包括多个接口,例如

<T extends String &amp; CharSequence &amp; List &amp; Comparator>

但只有第一个绑定可能是一个非接口。

 
 
Code问答: http://codewenda.com/topics/python/
Stackoverflow: Generic return type upper bound – interface vs. class – surprisingly valid code

*转载请注明本文链接以及stackoverflow的英文链接

发表评论

电子邮件地址不会被公开。 必填项已用*标注

44 − = 42