Arrays of Parameterized Types

Java-Arrays of Parameterized Types

Arrays of Parameterized Types

You cannot create an array of type-specific generic references. Attempting to create an array of type-specific generic, causes a compiler error.  For example, the following statement is not permitted and results in a compiler error message:

Arrays of Parameterized Types

This code is the simplest approach to creating an array of a generic type and the compiler tells you explicitly that creating a generic type array is forbidden. Why Java does not allow you to create arrays of generic types ? The first thing we need to do is recall how arrays work for regular Java types. An array is a kind of built-in collection of some base type of element. Furthermore, array types are true types in the Java language and are represented at runtime by unique class types.  This is where the trouble begins. Although arrays in Java act a lot like generic collections, they do not behave like Java generics with respect to their type relationships.

Arrays differ from generic types in two important ways. First, arrays are covariant, which means simply that if Sub is a subtype of Super, then the array type Sub[] is a subtype of Super[]. Generics, by contrast, are invariant: for any two distinct types Type1 and Type2, Gen<Type1> is neither a subtype nor a supertype of Gen< Type2>. You might think this means that generics are deficient, but arguably it is arrays that are deficient. For example:

Arrays of Parameterized Types

Either way you can’t put a String into a Integer container, but with an array you find out that you’ve made a mistake at runtime; with a Gen, you find out at compile time. Of course you’d rather find out at compile time. The second major difference between arrays and generics is that arrays are reified. This means that arrays know and enforce their element types at runtime. As noted above, if you try to store a String into an array of Integer, you’ll get an ArrayStoreException. Generics, by contrast, are implemented by erasure. This means that they enforce their type constraints only at compile time and discard (or erase) their element type information at runtime.

Because of these fundamental differences, arrays and generics do not mix well. For example, it is illegal to create an array of a generic type, a parameterized type, or a type parameter. None of these array creation expressions are legal: new Gen<T>[], new Gen<Intgeer>[], new T[]. All will result in generic array creation errors at compile time. Why is it illegal to create a generic array? Because it isn’t typesafe. If it were legal, casts generated by the compiler in an otherwise correct program could fail at runtime with a ClassCastException. This would violate the fundamental guarantee provided by the generic type system. Consider the following code fragment that demonstrates why generic array creation is illegal – won’t compile:

Arrays of Parameterized Types

Let’s pretend that line 1, which creates a generic array, is legal. Line 2 stores the Gen<Integer> array into an Object array variable, which is legal because arrays are covariant. Line 3 creates and stores the Gen<String> into the sole element of the Object array, which succeeds because generics are implemented by erasure: the runtime type of a Gen<String> instance is simply Gen, and the runtime type of a Gen<Integer>[] instance is Gen[]:

Arrays of Parameterized Types

So line 3 assignment doesn’t generate an ArrayStoreException. Now we’re in trouble. We’ve stored a Gen<String> instance into an array that is declared to hold only Gen<Integer> instances. In line 4, we retrieve the element from the sole gen object in this array. The compiler automatically casts the retrieved element to Integer, but it’s an String, so we get a ClassCastException at runtime. In order to prevent this from happening, line 1 (which creates a generic array) generates a compile-time error.

Note that only the creation of generic arrays is outlawed. You can declare a variable of array of generic type, Gen<Integer>[] is legal. But you can’t initialize it with a new Gen<Integer>[3]. By contrast, you can initialize it with an array of raw type, new Gen[3], but it is not safe. For example:

Arrays of Parameterized Types

Let’s pretend that line 1, which creates a raw type of Gen array and stores that array into an Gen<Integer> array variable. In line 2, we retrieve the sole element from the sole Gen object in this array. The compiler automatically casts the retrieved element to Integer, but it’s an String, so we get a ClassCastException at runtime. So, creation of an array of raw type is not safe. If you need to collect parameterized type objects, simply use an java.util.ArrayList: ArrayList<Gen<Integer>> is safe and effective.

Program

Arrays of Parameterized Types

Program Source

class Gen<T> {
    
    private T t1;

    Gen(T t) {
        t1 = t;
    }
    T getT() {
        return t1;
    }
}

public class Javaapp {

    public static void main(String[] args) {
        
        Gen anygenarray[] = new Gen[3];
        anygenarray[0] = new Gen<String>("Java");
        anygenarray[1] = new Gen<Integer>(50);
        anygenarray[2] = new Gen<Float>(26.5f);
 
        Gen<Integer> genintarray[] = anygenarray;
        Integer getint = genintarray[0].getT();
    }
}

Leave a Comment