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

标签 java generics java-8

这是来自第 3 方库 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<X>
  found: java.util.List<java.lang.Integer>
  reason: inference variable X has incompatible bounds
    equality constraints: java.lang.Integer
    upper bounds: java.lang.CharSequence

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

最佳答案

CharSequence是一个 interface .因此即使SomeClass不执行 CharSequence完全有可能创建一个类

class SubClass extends SomeClass implements CharSequence

因此你可以这样写

SomeClass c = getCharSequence();

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

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

<T extends Integer & CharSequence>

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

随着 List例如,您需要记住泛型既不是协变的也不是逆变的。这意味着如果 XY 的子类型, List<X>既不是 List<Y> 的子类型也不是父类(super class)型.自 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> )时,交集类型隐式出现。

欲了解更多信息,here是 JLS 的一部分,它解释了类型边界是如何工作的。您可以包含多个接口(interface),例如

<T extends String & CharSequence & List & Comparator>

但只有第一个边界可以是非接口(interface)。

关于java - 通用返回类型上限 - 接口(interface)与类 - 令人惊讶的有效代码,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/51720881/

相关文章:

java - 无法在 GridView 中显示包含 Pointer 字段的 Parse.com 对象的数据 - Android

java - 从 Java 调用时隐藏 BAT 文件窗口

java - 使用类型输入创建对象

java - 编译器是否能从另一个通用参数列表中找出其中一个?

java - 如何在 IntelliJ IDEA 13.1 中创建 Java 8 项目?

amazon-s3 - 执行多次下载并等待全部完成

java - 将整数表示为连续正整数之和

java - 从 dv 摄像机进行实时 RTMP 流传输的最佳方式

c# - 如何使用泛型变量执行数学运算?

java - 使用 Java 8 Lambda 表达式合并映射流