From Effective Java by Joshua Bloch,
- Arrays differ from generic type in two important ways. First arrays are covariant. Generics are invariant.
Covariant simply means if X is subtype of Y then X[] will also be sub type of Y[]. Arrays are covariant As string is subtype of Object So
String[] is subtype of Object[]
Invariant simply means irrespective of X being subtype of Y or not ,
List<X> will not be subType of List<Y>.
My question is why the decision to make arrays covariant in Java? There are other SO posts such as Why are Arrays invariant, but Lists covariant?, but they seem to be focussed on Scala and I am not able to follow.
May be this help:-
Generics are not covariant
Arrays in the Java language are covariant -- which means that if Integer extends Number (which it does), then not only is an Integer also a Number, but an Integer[] is also a
Number[]
, and you are free to pass or assign anInteger[]
where aNumber[]
is called for. (More formally, if Number is a supertype of Integer, thenNumber[]
is a supertype ofInteger[]
.) You might think the same is true of generic types as well -- thatList<Number>
is a supertype ofList<Integer>
, and that you can pass aList<Integer>
where aList<Number>
is expected. Unfortunately, it doesn't work that way.It turns out there's a good reason it doesn't work that way: It would break the type safety generics were supposed to provide. Imagine you could assign a
List<Integer>
to aList<Number>
. Then the following code would allow you to put something that wasn't an Integer into aList<Integer>
:Because ln is a
List<Number>
, adding a Float to it seems perfectly legal. But if ln were aliased withli
, then it would break the type-safety promise implicit in the definition of li -- that it is a list of integers, which is why generic types cannot be covariant.Arrays are covariant for at least two reasons:
It is useful for collections that hold information which will never change to be covariant. For a collection of T to be covariant, its backing store must also be covariant. While one could design an immutable
T
collection which did not use aT[]
as its backing store (e.g. using a tree or linked list), such a collection would be unlikely to perform as well as one backed by an array. One might argue that a better way to provide for covariant immutable collections would have been to define a "covariant immutable array" type they could use a backing store, but simply allowing array covariance was probably easier.Arrays will frequently be mutated by code which doesn't know what type of thing is going to be in them, but won't put into the array anything which wasn't read out of that same array. A prime example of this is sorting code. Conceptually it might have been possible for array types to include methods to swap or permute elements (such methods could be equally applicable to any array type), or define an "array manipulator" object which hold a reference to an array and one or more things that had been read from it, and could include methods to store previously-read items into the array from which they had come. If arrays were not covariant, user code would not be able to define such a type, but the runtime could have included some specialized methods.
The fact that arrays are covariant may be viewed as an ugly hack, but in most cases it facilitates the creation of working code.