Covariant Arrays in java

Definition

Covariant arrays mean an array of type T can hold elements of type T and the subtype of T.

public class ArraysCovariance {
   public static void main(String[] args) {
      
      Number[] numbers = new Number[3];

      Number num = 100;
      numbers[0] = 10;
      numbers[1] = 10.5;
      numbers[2] = 12l;
      numbers[3] = num;

      for (Number number : numbers) {
         System.out.println("Element is : "+number);
      }	
   }
}

Output : Element is : 10
         Element is : 10.5
         Element is : 12
         Element is : 100

Note* Here Array of type Number is holding Number datatype as well as subtype of Number ( Integer , Double , Long )

Array Subtyping

The subtyping rule says if S is a subtype of T then S[] is also a subtype of T[].

public class ArraysCovariance1 {
   public static void main(String[] args) {
      Number[] numbers = new Integer[2];
      numbers[0] = 10;
      numbers[1] = 12;
      for (Number number : numbers) {
         System.out.println("Element is : "+number);
      }
   }
}

Output : Element is : 10
         Element is : 12

Note* Integer is a subtype of Number hence Number[] is used as a reference for Integer[]

If S is not a subtype of T then S[] is not a subtype of T[]. Java throws a type mismatch compile-time exception if we try to assign S[] to T[].

public class ArraysCovariance1 {
   public static void main(String[] args) {
      Number[] numbers = new String[2];  // Compilation Error
      numbers[0] = 10;
      numbers[1] = 12;
      for (Number number : numbers) {
         System.out.println("Element is : "+number);
      }
   }
}

CE : Exception in thread “main” java.lang.Error: Unresolved compilation problem: Type mismatch: cannot convert from String[] to Number[]
at ArraysCovariance1.main(ArraysCovariance1.java)

Passing subtype array to supertype array

Consider a scenario when an Integer[] is created but a specific method requires a Number[] as an argument. So can we pass Integer[] to Number[]? Yes, this is possible with the help of array subtyping. As mentioned earlier if S is a subtype of T then S[] is also a subtype of T[].

public class ArraysCovariance2 {
   public static void main(String[] args) {
      Integer[] integers = new Integer[3];
      integers[0] = 10;
      integers[1] = 11;
      integers[2] = 12;
      printNumbers(integers);
}

   static void printNumbers(Number[] numbers) {
      for (Number number : numbers) {
         System.out.println("Element is : "+number);
      }
   }
}

Output : Element is : 10
         Element is : 11
         Element is : 12

Refiable type

Consider a scenario when we pass an Integer[] to a method that accepts Number[] and we manipulate the array in that method. Check the example below :

public class ArrayCovariance3 {
   public static void main(String[] args) {
      Integer[] integers = new Integer[4];
      integers[0] = 10;
      integers[1] = 11;
      integers[2] = 12;
      printNumbers(integers);
}
	
   static void printNumbers(Number[] numbers) {
      numbers[3] = 12L;  // Runtime Exception
      for (Number number : numbers) {
         System.out.println("Element is : "+number);
      }
   }
}

Output : Exception in thread “main” java.lang.ArrayStoreException: java.lang.Long at ArrayCovariance3.printNumbers(ArrayCovariance3.java) at
ArrayCovariance3.main(ArrayCovariance3.java)

The above code will throw a runtime exception because we can fool the compiler but we cannot fool the Java runtime environment. JRE will know the array was instantiated with Integer[] but now we are trying to add a Long data type to Integer[] in disguise of a Number[]. Hence java throws a runtime exception. So the array is termed a Refiable type

If you like this covariant array article please share it. If you want to add anything extra please comment below and write to me if I have gone wrong anywhere.

Leave a Comment