Categories
arrays generics instantiation java reflection

How to create a generic array in Java?

1204

Due to the implementation of Java generics, you can’t have code like this:

public class GenSet<E> {
    private E a[];

    public GenSet() {
        a = new E[INITIAL_ARRAY_LENGTH]; // error: generic array creation
    }
}

How can I implement this while maintaining type safety?

I saw a solution on the Java forums that goes like this:

import java.lang.reflect.Array;

class Stack<T> {
    public Stack(Class<T> clazz, int capacity) {
        array = (T[])Array.newInstance(clazz, capacity);
    }

    private final T[] array;
}

But I really don’t get what’s going on.

3

  • 19

    Do you really need to use an array here? What about using a Collection?

    – matt b

    Feb 9, 2009 at 18:34

  • 14

    Yes I also think that collections are more elegant to for this problem. But this is for a class assignment and they are required 🙁

    Feb 9, 2009 at 19:47

  • 4

    I do not understand why I need a reflect here.Java grammar is strange: like new java.util.HashMap<String,String>[10] is not valid. new java.util.HashMap<long,long>(10) is not valid. new long[][10] is not valid, new long[10][] is valid. That stuff make write a program that can write java program is more difficult then it looks like.

    Jun 30, 2017 at 2:46


765

I have to ask a question in return: is your GenSet “checked” or “unchecked”?
What does that mean?

  • Checked: strong typing. GenSet knows explicitly what type of objects it contains (i.e. its constructor was explicitly called with a Class<E> argument, and methods will throw an exception when they are passed arguments that are not of type E. See Collections.checkedCollection.

    -> in that case, you should write:

    public class GenSet<E> {
    
        private E[] a;
    
        public GenSet(Class<E> c, int s) {
            // Use Array native method to create array
            // of a type only known at run time
            @SuppressWarnings("unchecked")
            final E[] a = (E[]) Array.newInstance(c, s);
            this.a = a;
        }
    
        E get(int i) {
            return a[i];
        }
    }
    
  • Unchecked: weak typing. No type checking is actually done on any of the objects passed as argument.

    -> in that case, you should write

    public class GenSet<E> {
    
        private Object[] a;
    
        public GenSet(int s) {
            a = new Object[s];
        }
    
        E get(int i) {
            @SuppressWarnings("unchecked")
            final E e = (E) a[i];
            return e;
        }
    }
    

    Note that the component type of the array should be the erasure of the type parameter:

    public class GenSet<E extends Foo> { // E has an upper bound of Foo
    
        private Foo[] a; // E erases to Foo, so use Foo[]
    
        public GenSet(int s) {
            a = new Foo[s];
        }
    
        ...
    }
    

All of this results from a known, and deliberate, weakness of generics in Java: it was implemented using erasure, so “generic” classes don’t know what type argument they were created with at run time, and therefore can not provide type-safety unless some explicit mechanism (type-checking) is implemented.

8

  • 8

    What would performance-wise be the best option? I need to get elements from this array quite often (within a loop). So a collection is probably slower, but which of these two is fastest?

    Sep 8, 2012 at 3:52


  • 4

    And if the generic type is bounded, the backing array should be of the bounding type.

    – Mordechai

    Apr 8, 2013 at 5:59

  • 5

    @AaronDigulla Just to clarify that’s not assignment, but initialization of a local variable. You can’t annotate an expression/statement.

    – kennytm

    Sep 26, 2013 at 12:17

  • 1

    @Varkhan Is there a way to resize these arrays from within the class implementation. For example if I want to resize after overflow like ArrayList. I looked up the Implementation of ArrayList they have Object[] EMPTY_ELEMENTDATA = {} for storage. Can I use this mechanism to resize without knowing the type using generics?

    Aug 28, 2014 at 17:53


  • 2

    For those who want to make a method with a generic type (which was what I was looking for), use this: public void <T> T[] newArray(Class<T> type, int length) { ... }

    Mar 13, 2015 at 14:44

262

You can do this:

E[] arr = (E[])new Object[INITIAL_ARRAY_LENGTH];

This is one of the suggested ways of implementing a generic collection in Effective Java; Item 26. No type errors, no need to cast the array repeatedly. However this triggers a warning because it is potentially dangerous, and should be used with caution. As detailed in the comments, this Object[] is now masquerading as our E[] type, and can cause unexpected errors or ClassCastExceptions if used unsafely.

As a rule of thumb, this behavior is safe as long as the cast array is used internally (e.g. to back a data structure), and not returned or exposed to client code. Should you need to return an array of a generic type to other code, the reflection Array class you mention is the right way to go.


Worth mentioning that wherever possible, you’ll have a much happier time working with Lists rather than arrays if you’re using generics. Certainly sometimes you don’t have a choice, but using the collections framework is far more robust.

17

  • 49

    This will not work if the array is treated as a typed array of any kind, such as String[] s=b; in the above test() method. That’s because the array of E isn’t really, it’s Object[]. This matters if you want, e.g. a List<String>[] – you can’t use an Object[] for that, you must have a List[] specifically. Which is why you need to use the reflected Class<?> array creation.

    Oct 11, 2010 at 16:09


  • 8

    The corner-case/problem is if you want to do, for example, public E[] toArray() { return (E[])internalArray.clone(); } when internalArray is typed as E[], and is therefore actually an Object[]. This fails at runtime with a type-cast exception because an Object[] cannot be assigned to an array of whatever type E happens to be.

    Aug 10, 2011 at 20:04


  • 18

    Basically, this approach will work as long as you do not return the array or pass it or store it in some place outside of the class that requires an array of a certain type. As long as you’re inside the class you’re fine because E is erased. It’s “dangerous” because if you try to return it or something, you get no warning that it’s unsafe. But if you’re careful then it works.

    – newacct

    Sep 23, 2011 at 22:07

  • 3

    It is quite safe. In E[] b = (E[])new Object[1]; you can clearly see that the only reference to the created array is b and that the type of b is E[]. Therefore there is no danger of you accidentally accessing the same array through a different variable of a different type. If instead, you had Object[] a = new Object[1]; E[]b = (E[])a; then you would need to be paranoid about how you use a.

    Jan 21, 2012 at 19:53


  • 5

    At least in Java 1.6, this generates a warning: “Unchecked cast from Object[] to T[]”

    – Quantum7

    Mar 24, 2012 at 0:42

66

Here’s how to use generics to get an array of precisely the type you’re looking for while preserving type safety (as opposed to the other answers, which will either give you back an Object array or result in warnings at compile time):

import java.lang.reflect.Array;  

public class GenSet<E> {  
    private E[] a;  

    public GenSet(Class<E[]> clazz, int length) {  
        a = clazz.cast(Array.newInstance(clazz.getComponentType(), length));  
    }  

    public static void main(String[] args) {  
        GenSet<String> foo = new GenSet<String>(String[].class, 1);  
        String[] bar = foo.a;  
        foo.a[0] = "xyzzy";  
        String baz = foo.a[0];  
    }  
}

That compiles without warnings, and as you can see in main, for whatever type you declare an instance of GenSet as, you can assign a to an array of that type, and you can assign an element from a to a variable of that type, meaning that the array and the values in the array are of the correct type.

It works by using class literals as runtime type tokens, as discussed in the Java Tutorials. Class literals are treated by the compiler as instances of java.lang.Class. To use one, simply follow the name of a class with .class. So, String.class acts as a Class object representing the class String. This also works for interfaces, enums, any-dimensional arrays (e.g. String[].class), primitives (e.g. int.class), and the keyword void (i.e. void.class).

Class itself is generic (declared as Class<T>, where T stands for the type that the Class object is representing), meaning that the type of String.class is Class<String>.

So, whenever you call the constructor for GenSet, you pass in a class literal for the first argument representing an array of the GenSet instance’s declared type (e.g. String[].class for GenSet<String>). Note that you won’t be able to get an array of primitives, since primitives can’t be used for type variables.

Inside the constructor, calling the method cast returns the passed Object argument cast to the class represented by the Class object on which the method was called. Calling the static method newInstance in java.lang.reflect.Array returns as an Object an array of the type represented by the Class object passed as the first argument and of the length specified by the int passed as the second argument. Calling the method getComponentType returns a Class object representing the component type of the array represented by the Class object on which the method was called (e.g. String.class for String[].class, null if the Class object doesn’t represent an array).

That last sentence isn’t entirely accurate. Calling String[].class.getComponentType() returns a Class object representing the class String, but its type is Class<?>, not Class<String>, which is why you can’t do something like the following.

String foo = String[].class.getComponentType().cast("bar"); // won't compile

Same goes for every method in Class that returns a Class object.

Regarding Joachim Sauer’s comment on this answer (I don’t have enough reputation to comment on it myself), the example using the cast to T[] will result in a warning because the compiler can’t guarantee type safety in that case.


Edit regarding Ingo’s comments:

public static <T> T[] newArray(Class<T[]> type, int size) {
   return type.cast(Array.newInstance(type.getComponentType(), size));
}

13

  • 5

    This is useless, it is only a complicated way to write new String[…]. But what is really needed is something like public static <T> T[] newArray(int size) { … }, and this simply does not exist in java noir can it be simulated with reflection – the reason is that information about how a generic type is instantiated is not available at runtime.

    – Ingo

    Mar 21, 2011 at 10:11


  • 4

    @Ingo What are you talking about? My code can be used to create an array of any type.

    – gdejohn

    Mar 23, 2011 at 12:34

  • 3

    @Charlatan: Sure, but so can new []. The question is: who knows the type and when. Therefore, if all you have is a generic type, you can’t.

    – Ingo

    Mar 23, 2011 at 12:48

  • 2

    I don’t doubt that. The point is, you don’t get a Class object at runtime for generic type X.

    – Ingo

    Mar 23, 2011 at 12:58

  • 2

    Almost. I admit that this is more than what can be achieved with new[]. In practice, this will almost always do the job. However, it is still not possible, for instance, to write a container class parameterized with E that has a method E[] toArray() and that indeed returns a true E[] array. Your code could be applied only when there is at least one E-object in the collection. So, a general solution is impossible.

    – Ingo

    Mar 23, 2011 at 13:31