这是来自第三方库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
CharSequence
Integer y = getString();
给出错误(按预期)
incompatible types: inference variable X has incompatible upper bounds java.lang.Integer,java.lang.String
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>给出了一个错误,如预期的那样:
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
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();不呢?
CharSequence是一个interface。因此,即使SomeClass不实现CharSequence,也完全有可能创建一个类
interface
SomeClass
class SubClass extends SomeClass implements CharSequence
因此你可以写
SomeClass c = getCharSequence();
因为推断的类型X是相交类型SomeClass & CharSequence。
X
SomeClass & CharSequence
在某些情况下,这是有点奇怪的,Integer因为它Integer是最终的,但final在这些规则中没有任何作用。例如你可以写
final
<T extends Integer & CharSequence>
另一方面,String由于不是interface,所以不可能扩展SomeClass以获得的子类型String,因为Java不支持类的多重继承。
String
在该List示例中,您需要记住,泛型既不是协变也不是协变。这意味着if X是的子类型Y,List<X>既不是的子类型也不是的超类型List<Y>。由于Integer未实现CharSequence,因此无法List<Integer>在您的doCharSequence方法中使用。
List
Y
List<X>
List<Y>
doCharSequence
您可以,但是可以将其编译
<T extends Integer & CharSequence> void foo(List<T> list) { doCharSequence(list); }
如果你有一个方法 返回 一个List<T>像这样的:
List<T>
static <T extends CharSequence> List<T> foo()
你可以做
List<? extends Integer> list = foo();
同样,这是因为推断的类型是,Integer & CharSequence并且这是的子类型Integer。
Integer & CharSequence
当您指定多个边界(例如<T extends SomeClass & CharSequence>)时,交叉点类型隐式出现。
<T extends SomeClass & CharSequence>
有关更多信息,这是JLS的一部分,其中解释了类型边界的工作方式。您可以包括多个接口,例如
<T extends String & CharSequence & List & Comparator>
但只有第一个边界可以是非接口。