4

In the last paragraph of Item 25 in the Effective Java (2nd), it's said:

Arrays and generics have very different type rules. Arrays are covariant and reified; generics are invariant and erased.

Could someone give better definitions of the bolded terms in relation to arrays and generics in Java? I wouldn't mind some examples either.

Jason
  • 3,677
  • 12
  • 24
flowjow
  • 161
  • 2
  • 13
  • [this eric lippert blog](http://blogs.msdn.com/b/ericlippert/archive/tags/covariance+and+contravariance/default.aspx) explains variance, although it applies more to c#. Have you tried wikipedia? – D. Ben Knoble Aug 18 '15 at 17:17
  • 1
    I think I'll get more explicit answer to this question here at SO. I also think that there are other people reading this excellent book and might have a similar question as I have. – flowjow Aug 18 '15 at 17:26

1 Answers1

4

You didn't mention if you were confused about a particular concept, so I'm going to try to just give basic definitions of covariance and invariance.

Covariance preserves type ordering, invariance does not. What this means is that sub-typing is or isn't preserved (inverted in the case of contravariance).

So, if you had the following class

public class A {

  public void go() {

    System.out.println("A");
  }
}

and...

public class B extends A {

  @Override
  public void go() {

    System.out.println("B");
  }
}

With covariant typing (e.g. arrays), the function

public static void go(A[] as) {

  for (A a : as)
    a.go();
}

is perfectly valid used as

A[] as = new A[8];
B[] bs = new B[8];

go(as);
go(bs);

In other words, array types are exposed to the runtime or reified.

With invariant typing (e.g. generics), sub-typing isn't preserved. So, for example, X<B> would have no type relation to X<A> other than X. This is partially a consequence of generic types not being exposed to the runtime or erased.

However, you can still explicitly express covariance and contravariance in Java using extends and super respectively. For example with the class

public class X<T extends A> {

  private T t_;

  public X(T t) {
   t_ = t;
  }

  public void go() {

    t_.go();
  }
}

The function

public static void go(X<?> x) {

  x.go();
}

would be valid used as

X<A> xa = new X<A>(a);
X<B> xb = new X<B>(b);

go(xa);
go(xb);
Jason
  • 3,677
  • 12
  • 24