小编典典

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

all

这是来自 3rd 方库 API 的真实示例,但经过简化。

使用 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();

给出错误(如预期的那样)

incompatible types: inference variable X has incompatible upper bounds

java.lang.Integer,java.lang.String

有人可以解释为什么这种行为会被认为是有效的吗?会有什么用?

客户端不知道这个调用是不安全的——客户端的代码在没有警告的情况下编译。为什么编译器不会对此发出警告/发出错误?

此外,它与此示例有何不同:

<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>会出现错误:

method doCharSequence in class generic.GenericTest cannot be applied to

given types;
required: java.util.List
found: java.util.List
reason: inference variable X has incompatible bounds
equality constraints: java.lang.Integer
upper bounds: java.lang.CharSequence

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


阅读 90

收藏
2022-08-27

共1个答案

小编典典

CharSequence是一个interface。因此,即使SomeClass没有实现CharSequence,也完全有可能创建一个类

class SubClass extends SomeClass implements CharSequence

因此你可以写

SomeClass c = getCharSequence();

因为推断的类型X是交集类型SomeClass & CharSequence

Integer这在因为Integer是最终的情况下有点奇怪,但final在这些规则中没有任何作用。例如你可以写

<T extends Integer & CharSequence>

另一方面,Stringis 不是interface,因此不可能扩展SomeClass以获得 的子类型String,因为 java
不支持类的多重继承。

在这个List例子中,你需要记住泛型既不是协变的也不是逆变的。这意味着 ifX是 的子类型Y,List<X>既不是 的子类型也不是
的超类型List<Y>。由于Integer未实现CharSequence,因此您不能List<Integer>在您的doCharSequence方法中使用。

但是,您可以编译它

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

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

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

你可以做

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

同样,这是因为推断的类型是Integer & CharSequence并且这是 的子类型Integer

<T extends SomeClass & CharSequence>当您指定多个边界(例如)时,交叉点类型会隐式出现。

有关更多信息,请参阅
JLS部分内容,其中解释了类型边界的工作方式。您可以包含多个接口,例如

<T extends String & CharSequence & List & Comparator>

但只有第一个界限可能是非接口。

2022-08-27