Type rules of arrays and generics in Java

159 Views Asked by At

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.

1

There are 1 best solutions below

0
On BEST ANSWER

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);