Вы не упомянули, если вас запутала конкретная концепция, поэтому я попытаюсь просто дать основные определения ковариантности и инвариантности.
Ковариация сохраняет порядок типов, инвариантность — нет. Это означает, что подтипы сохраняются или не сохраняются (инвертируются в случае контравариантности).
Итак, если бы у вас был следующий класс
public class A {
public void go() {
System.out.println("A");
}
}
а также...
public class B extends A {
@Override
public void go() {
System.out.println("B");
}
}
При ковариантной типизации (например, массивы) функция
public static void go(A[] as) {
for (A a : as)
a.go();
}
вполне допустимо использовать как
A[] as = new A[8];
B[] bs = new B[8];
go(as);
go(bs);
Другими словами, типы массивов доступны среде выполнения или овеществлены.
При инвариантной типизации (например, дженерики) подтипизация не сохраняется. Так, например, X<B>
не будет иметь отношения типа к X<A>
, кроме X
. Частично это является следствием того, что универсальные типы не отображаются во время выполнения или стираются.
Однако вы все равно можете явно выразить ковариантность и контравариантность в Java, используя extends
и super
соответственно. Например с классом
public class X<T extends A> {
private T t_;
public X(T t) {
t_ = t;
}
public void go() {
t_.go();
}
}
Функция
public static void go(X<?> x) {
x.go();
}
будет действителен в качестве
X<A> xa = new X<A>(a);
X<B> xb = new X<B>(b);
go(xa);
go(xb);
person
Jason
schedule
18.08.2015