1

I'm studying for my Java midterm but I have some problems with the reified type. Here there is a class that is wrong, but I cannot understand why. Can someone help me and maybe give me some explanation? The error is, of course, related to the reified type.

class Conversion {
    public static <T> T[] toArray(Collection<T> c) {
        T[] a = new T[c.size()];
        int i = 0;
        for (T x: c) a[i++] = x;
        return a;
   }
}
Mogsdad
  • 40,814
  • 19
  • 140
  • 246
Francesco
  • 461
  • 1
  • 6
  • 13
  • 1
    The simple answer is that you can't create an array with the item type coming from a type parameter. – biziclop Oct 26 '15 at 20:03

3 Answers3

5

An array is a reified type. This means that the exact type of the array is known at runtime. So at runtime there is a difference between, for example, String[] and Integer[].

This is not the case with generics. Generics are a compile-time construct: they are used to check the types at compile-time, but at runtime the exact types are not available anymore. At runtime, the type parameters are just Object (or if the type parameter has an upper bound, its upper bound). So at run-time, there is no difference in the type of Collection<String> and Collection<Integer>.

Now, there is a problem when you want to create an array of a type parameter. At runtime it is unknown what T is, so if you write new T[10], the Java runtime doesn't known what kind of array is to be created, a String[] or a Integer[]. That's why you cannot create an array in this way.

There are a few work-arounds, none of which is entirely satisfactory. The usual solution is to create an Object[], and cast it to the kind of array you want:

T[] theArray = (T[]) new Object[size];

However, you have to remember that this is very unsafe. You should only do this if the scope of the created arrow is small, so that you can manually make sure that the array will only contain T instances and will never be assigned to anything that cannot hold it. The following code demonstrates the problem:

public class Foo<T extends Comparable> {    
    T[] createArray() {
        return (T[])new Object[1];
    }

    public static void main(String... args) {
        Foo<String> foo = new Foo<>();
        String[] ss = foo.createArray(); // here
    }
}

The line marked with here throws an exception, because you are trying to cast an Object[] to a String[]!

If you really need an array of the correct run-time type, you need to use reflection. Obtain a type token (of type Class<T>) of the type you need, and use Array.newInstance(type, cize) to create the array, for example:

public T[] createArray(Class<T> type, int size) {
    return (T[]) Array.newInstance(type, size);
}
Hoopje
  • 11,820
  • 6
  • 29
  • 47
3

Reifiable type is defined by the JLS as:

A type is reifiable if and only if one of the following holds:

  • It refers to a non-generic class or interface type declaration.
  • It is a parameterized type in which all type arguments are unbounded wildcards (§4.5.1).
  • It is a raw type (§4.8).
  • It is a primitive type (§4.2).
  • It is an array type (§10.1) whose element type is reifiable.
  • It is a nested type where, for each type T separated by a ".", T itself is reifiable.

See also the notes that follow §4.7, the reasoning is described in great detail.

Your type parameter is none of the above, therefore it is not reifiable. And thus can't be used in an array creation expression:

It is a compile-time error if the ClassOrInterfaceType does not denote a reifiable type (§4.7). Otherwise, the ClassOrInterfaceType may name any named reference type, even an abstract class type (§8.1.1.1) or an interface type.

biziclop
  • 46,403
  • 12
  • 73
  • 97
2

You can't create an array of a generic type. The compiler likely complains with something like "generic array creation". There's no nice way around this, but there is a way to do this:

public static <T> T[] toArray(Class<T> type, Collection<T> c) {
    T[] a = (T[]) Array.newInstance(type, c.size())
    …
}

You'll need Class<T> for this, but it does work :)

akaIDIOT
  • 9,011
  • 3
  • 24
  • 30
  • So what exactly do Class type? – Francesco Oct 26 '15 at 20:16
  • 1
    `Class` is the class for type `T`, just as `Class` is the class for `String`. `Array.newInstance` needs an explicit reference to it, and `T.class` won't work as `T` itself is not reifiable, so the caller of `toArray` would need to supply it. – akaIDIOT Oct 26 '15 at 21:32