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.)

4
  • 2
    You might want to look at stackoverflow.com/questions/529085/… and stackoverflow.com/questions/3865946/… . Commented Mar 26, 2011 at 21:37
  • 2
    What is your reason for insisting on arrays rather than other collection types? Commented Mar 26, 2011 at 21:38
  • You are casting an Object[][] to an A<String>[][], the 2 are not compatible. Commented Mar 26, 2011 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. Commented Mar 26, 2011 at 22:01

7 Answers 7

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];
Sign up to request clarification or add additional context in comments.

2 Comments

I believe the following also works: ` @SuppressWarnings("unchecked") A<String>[][] array = (A<String>[][]) java.lang.reflect.Array.newInstance(A.class,2,3);`
@dsg You guys are extremely funny. Array.newInstance(A.class, 2, 3) is exactly the same as new A[2][3]
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"

2 Comments

This is cool! I suppose you can do A<String>[][] array = (A<String>[][]) new A<?>[2][3];
yeah, but in this way you'll have unchecked cast warning, to prevent it add @SuppressWarnings("unchecked")
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);

3 Comments

Is there a way to get the class of the basic object without instantiating it?
While I'm glad you figured this out, the burning question is still why go to all this trouble over using ArrayList<ArrayList<A<String>>> ?
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.
1

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

Comments

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
    }

}

Comments

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.

Comments

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

Comments

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.