Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

How to create a generic array in Java?

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.

like image 311
tatsuhirosatou Avatar asked Feb 09 '09 17:02

tatsuhirosatou


People also ask

Why we Cannot create a generic array in Java?

If generic array creation were legal, then compiler generated casts would correct the program at compile time but it can fail at runtime, which violates the core fundamental system of generic types.

What is generic array type?

A generic type is a generic class or interface that is parameterized over types. The following Box class will be modified to demonstrate the concept.

Can you instantiate generic arrays?

Although we cannot instantiate a generic array of a specific type parameter, we can pass an already created array to a generic class constructor.


2 Answers

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.

like image 30
dimo414 Avatar answered Oct 21 '22 15:10

dimo414


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.

like image 80
Varkhan Avatar answered Oct 21 '22 14:10

Varkhan