这是来自第 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
例如,您需要记住泛型既不是协变的也不是逆变的。这意味着如果 X
是 Y
的子类型, 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/