分配给多级通配符

Łuk*_*asz 14 java generics bounded-wildcard

简单的课程:

class Pair<K,V> {

}
Run Code Online (Sandbox Code Playgroud)

还有一些任务:

Collection<Pair<String,Long>> c1 = new ArrayList<Pair<String,Long>>();
Collection<Pair<String,Long>> c2 = c1; // ok
Collection<Pair<String,?>> c3 = c1; // this does not compile
Collection<? extends Pair<String,?>> c4 = c1; // ok
Run Code Online (Sandbox Code Playgroud)

为什么第三个子弹不能编译而第四个完全合法?

编译错误:

Type mismatch: cannot convert from Collection<Pair<String,Long>> to Collection<Pair<String,?>>
Run Code Online (Sandbox Code Playgroud)

gex*_*ide 16

我将尝试使用两个简单的规则来解释Java泛型.这些规则足以回答你的问题,基本上足以记住几乎所有情况:

  1. 两种通用类型X<A>,X<B>除非是可分配的A = B.即,默认情况下,泛型是不变的.
  2. 通配符允许分配X<A>:
    • X<?>
    • to X<? extends T>iff A可赋值给T(递归地应用规则AT)
    • to X<? super T>iff T可赋值给A(递归地应用规则TA)

案件 c3 = c1

在您的示例中,您尝试分配Collection<Pair<String,Long>>Collection<Pair<String,?>>.也就是说,你的情况A = Pair<String,Long>B = Pair<String,?>.由于这些类型不相等,它们不可分配; 他们违反了规则1.

问题是,为什么通配符没有帮助?答案很简单:
规则2 不是传递性的.即,X<X<A>>不能被指责X<X<?>>,最外层必须有一个通配符; 否则规则2不适用于最外层.

案件 c4 = c1

在这里,你有一个外部类型的通配符.因为它是外部类型,所以规则2开始:A = Pair<String,?>可分配给B = ? extends Pair<String,Long>(再次,因为规则2).因此,这是合法的.

一般的做法

以下是检查任何复杂泛型类型的方法:只需使用这两个规则逐级检查每个泛型级别.从最外层开始.一旦某个级别违反规则,您就知道该分配是非法的; 如果所有级别都遵守规则,那么分配是合法的.让我们再次考虑你的类型:

X = Collection<Pair<String,Long>>
Y = Collection<Pair<String,?>>
Z = Collection<? extends Pair<String,?>> 
Run Code Online (Sandbox Code Playgroud)

X可分配给Y吗?

// Outermost level:
A = Pair<String,Long>, B = Pair<String,?>
  => B is no wildcard and A != B (Rule 1), so this is illegal!
Run Code Online (Sandbox Code Playgroud)

X可分配给Z吗?

// Outermost level:
A = Pair<String,Long>, B = ? extends Pair<String,?>
  => We got a wildcard, so Rule 2 states this is legal if the inner level is legal
// Inner level: (we have to check both parameters)
A = String, B = String => Equal, Rule 1 applies, fine!
A = Long, B = ? => B is wildcard, Rule 2 applies, fine!
Run Code Online (Sandbox Code Playgroud)

要记住的简单规则

每个级别的通用嵌套要么必须完全相同(A=B),要么B需要在此级别中包含通配符.