8

How do I make a multidimensional array of generic items in java?

Consider the class:

class A<T>
  {
    T t;
    public A(T t) { this.t = t; }
  }

When I try to create a multidimensional array:

A<String>[][] array = new A<String>[2][3];

I get the following error:

generic array creation
A<String>[][] array = new A<String>[2][3];
                      ^

I tried the following:

A<String>[][] array = (A<String>[][]) (new Object[2]3]);

But that just throws: java.lang.ClassCastException

What's the fix?

(I anticipate people recommending to use lists. Please explain how to achieve this using arrays.)

dsg
  • 12,504
  • 19
  • 64
  • 109
  • 2
    You might want to look at http://stackoverflow.com/questions/529085/java-how-to-generic-array-creation and http://stackoverflow.com/questions/3865946/error-generic-array-creation . – Gareth McCaughan Mar 26 '11 at 21:37
  • 2
    What is your reason for insisting on arrays rather than other collection types? – Gareth McCaughan Mar 26 '11 at 21:38
  • You are casting an Object[][] to an A[][], the 2 are not compatible. – katsharp Mar 26 '11 at 21:43
  • @Gareth McCaughan -- Arrays are easier to index than lists. `array[i][j]` is more legible than `array.get(i).get(j)`. When you're coding a complex algorithm, this is really helpful. – dsg Mar 26 '11 at 22:01

7 Answers7

4

I was able to do something like this

    @SuppressWarnings("unchecked") 
    A<String>[][] array = (A<String>[][]) Array.newInstance(new A<String>("dummy").getClass(), 2, 3);

EDIT:

from @dsg's suggestion the following skips the creation of a temporary object.

    @SuppressWarnings("unchecked") 
    A<String>[][] array = (A<String>[][]) Array.newInstance(A.class, 2, 3);

or (from @irreputable's suggestion)

 @SuppressWarnings("unchecked")
 A<String>[][] array = new A[2][3];
Bala R
  • 101,930
  • 22
  • 186
  • 204
  • I believe the following also works: ` @SuppressWarnings("unchecked") A[][] array = (A[][]) java.lang.reflect.Array.newInstance(A.class,2,3);` – dsg Mar 26 '11 at 22:15
  • 2
    @dsg You guys are extremely funny. `Array.newInstance(A.class, 2, 3)` is exactly the same as `new A[2][3]` – irreputable Mar 27 '11 at 00:01
2

You can't create an array of type-specific generic in simple way.

List<String>[] list = new List<String>[2]; //Illegal
List<?> aa[] = new List<?>[2]; // OK
...
A<?>[][] array = new A<?>[2][3]; // OK
A[0][0] = new A<String>(...);

This is an interesting article about Java 1.5 generics, "Java theory and practice: Generics gotchas"

lukastymo
  • 23,992
  • 12
  • 50
  • 66
1

Thanks to the comments I was able to piece together a solution.

As we saw, A<String>[][] array = new A<String>[2][3]; does not work.

Here how to construct a 2x3 array of A<String> objects that does work:

// get the class of the basic object
Class c = new A<String>("t").getClass();

// get the class of the inner array
A<String>[] a0 = (A<String>[]) java.lang.reflect.Array.newInstance(c, 0);

// construct the outer array
A<String>[][] array = (A<String>[][]) java.lang.reflect.Array.newInstance(a0.getClass(), 2); 

// fill it with instances of the inner array
for (int i = 0; i < 2; ++ i)
{   
  array[i] = (A<String>[]) java.lang.reflect.Array.newInstance(c, 3); 
}

A much cleaner version (Thanks, @Balla R):

@SuppressWarnings("unchecked")
A<String>[][] array = (A<String>[][]) java.lang.reflect.Array.newInstance(A.class,2,3);
dsg
  • 12,504
  • 19
  • 64
  • 109
  • Is there a way to get the class of the basic object without instantiating it? – dsg Mar 26 '11 at 21:59
  • While I'm glad you figured this out, the burning question is still why go to all this trouble over using `ArrayList>>` ? – Brian Roach Mar 26 '11 at 22:05
  • no, that's the problem. Before you instantiate it, there's not a way to determine its type. See my answer, you can use `A>[][]` for your array. – Brian Roach Mar 26 '11 at 22:24
1

Why don't you do something like this: (non-generic)

String[][] non_generic_array = new String[][];

And make a utility class to implement the functions you made in A<T> (as I suppose there are). Eg:

When you had this in A:

public class A<T>
{
    T obj;
    public A(T obj) { this.obj = obj; }

    public void someFunction() { ... }
}

You can make a utility class:

public class AUtils
{

    public static <T> void someFunction(T obj)
    {
        // Here your code, applied to obj
    }

}
BenMorel
  • 30,280
  • 40
  • 163
  • 285
Martijn Courteaux
  • 63,780
  • 43
  • 187
  • 279
1

new A[][] and cast it to A<String>[][]

irreputable
  • 42,827
  • 9
  • 59
  • 89
0

Hmm, I thought Java Arrays (as of Java 6) didn't support generics. One of my biggest "wtf" when I started programming with generics in java.

Gubatron
  • 5,581
  • 5
  • 31
  • 35
0
class A<T> 
{
    T s;

    public A(T t)
    {
        s = t;
    }

    public String getType()
    {
        return s.getClass().toString();
    }

    public T getThing()
    {
        return s;
    }
}

public static void main(String[] args) 
{
    A<?>[][] a = new A<?>[2][3];
    a[0][1] = new A<String>("hi");

    System.out.println(a[0][1].getType());
    System.out.println(a[0][1].getThing());

    A<String> b = (A<String>) a[0][1];
}

output:

class java.lang.String

hi

Community
  • 1
  • 1
Brian Roach
  • 72,790
  • 10
  • 128
  • 154