4

Possible Duplicate:
Java how to: Generic Array creation

How to create an array of type T[] in Java? I can't use Arrays.newInstance() since I have no objects of Class<T>. Is there a generic version of newInstance somewhere?

My method prototype follows:

public <T> T[][] distribute(T ... balls) {
   T[][] answer = ????

   // filling answer with data

   return answer;

}

UPDATE

Sorry in example above I can take class from balls. But suppose I have no such a variable.

public <T> T[][] distribute() {
   T[][] answer = ????

   // filling answer with data

   return answer;

}

or

class<T> {
   public T[][] distribute() {

      T[][] answer = ????

      // filling answer with data

      return answer;

   }
}

UPDATE2

This example also does not work:

public abstract class GenericArray<T> {

abstract public T create();

public T[] gen1() {
    T[] ans = (T[]) new Object[3];
    ans[0] = create();
    ans[1] = create();
    ans[2] = create();
    return ans;
}

public Integer[] gen2() {
    Integer[] ans = new Integer[3];
    ans[0] = new Integer(0);
    ans[1] = new Integer(0);
    ans[2] = new Integer(0);
    return ans;
}

public static void main(String[] args) {

    GenericArray<Integer> a = new GenericArray<Integer>() {

        @Override
        public Integer create() {
            return new Integer(0);
        }
    };

    Integer[] b = a.gen2();
    Integer[] c = a.gen1(); // this causes ClassCastException

    System.out.println("done");

}

}
Community
  • 1
  • 1
Dims
  • 47,675
  • 117
  • 331
  • 600
  • Why can't you get a `Class` from one of the `balls` varargs, assuming there is one? `if(balls.length > 0) Class clazz = balls[0].getClass();` At any rate, you're inevitably going to hear the "arrays and generics don't play nicely together" saw. – Matt Ball Aug 18 '12 at 17:07
  • The easiest way is to not use arrays, use a `Collection` of some sort. – Jeffrey Aug 18 '12 at 17:21

4 Answers4

6

1. Arrays are Not Generic

2. Thats the reason Arrays are checked during compile as well as runtime, where as Collections can be Generic and its checked only during the compile time....

Kumar Vivek Mitra
  • 33,294
  • 6
  • 48
  • 75
  • So it is impossible to create an array of a type when having only a generoc information? – Dims Aug 18 '12 at 17:30
  • You can use something like this `@SuppressWarnings("unchecked") B[] arr = new B[3];` but you need to suppress the compiler warning.... but why do it when the generic info are not present during the runtime, and moreover I dont prefer using arrays when i working in java. Collection provides far more flexibility – Kumar Vivek Mitra Aug 18 '12 at 17:35
  • 1
    Yes. Or, to be more precise: You do not have the generics information to begin with, as it is erased at runtime (at least in pure java). This is a compile-time feature that is lost completely once your application runs. – sarcan Aug 18 '12 at 17:35
  • @sarcan ya...and that process is called `Erasure`, where the `compiler removes the Type Parameter and Argument Parameters from the class , method, etc..`. Making it of Raw type (Raw type is a generic class or interface name without the Type arguments – Kumar Vivek Mitra Aug 18 '12 at 17:38
1

(T[][]) new Object[size][size]

Amit Deshpande
  • 19,001
  • 4
  • 46
  • 72
1

What you ask is not possible. An array knows its component type at runtime, and arrays of different component types are different runtime types. That's why when you create the array, you need to know the component type at runtime.

Since your method is generic over T, the caller can dictate the T it wants to use to the compiler every time it calls this method. So consider how absurd this is:

String[][] foo = this.<String>distribute();
Integer[][] bar = this.<Integer>distribute();

The compiled code on the right side of this is identical for the two lines. The .<String> stuff is just hints to the compiler, and do not affect the compiled code. So this means that distribute() must return something that is both String[][] and Integer[][] (which is then checked at runtime, since String[][] and Integer[][] are reified runtime types). The only value that can satisfy this is null.

(You might ask, why does this problem not occur for methods that return List<T>? The answer is that, unlike for arrays, there is only one class List at runtime. And lists do not know their component types at runtime. So a new ArrayList<Foo>() and a new ArrayList<Bar>() are exactly the same at runtime. So they don't have this problem.)

Another analogy of what is happening here: So array types have an inheritance pattern that follows the inheritance of their component types. So Integer[][] is a subclass of Object[][]. And in fact, all T[][] are subclasses of Object[][]. So instead of Object[][] and its subclasses, let's consider a non-array class, MyBaseClass, which has a bunch of subclasses. Then, what you are basically asking is to be able to generically create an instance of an unknown subclass of MyBaseClass (determined by a type parameter).

<T extends MyBaseClass> T distribute() {
    T answer = //...?
    return answer;
}

I hope you can see why this is impossible.

newacct
  • 119,665
  • 29
  • 163
  • 224
0

Do: T[][] answer = (T[][]) new Object[][];
T will be erased anyway by compiler to Object. Of course you need to know the size of the array.

Update:
In your new example you get the exception here:
Integer[] c = a.gen1(); // this causes ClassCastException
Because you are trying to cast an Object[] to an Integer[]. Not possible.
What you get back is an Object[] but containing Integer references. So you would need to do:

Object[] c = a.gen1();
for(Object n:c){  
    Integer nn = (Integer) n;  
}  

This is ok since n is an Integer.
But as a general rule: If you need to collect parameterized type objects, simply use an ArrayList. In your example where you don't even have the actual class to instantiate the array via reflection it is the only sensible choice

Cratylus
  • 52,998
  • 69
  • 209
  • 339
  • 1
    Won't this cause `ClassCastException` at runtime? – Dims Aug 18 '12 at 17:12
  • No because the type arguments `T` will be erased by the compiler and it will be replaced by `Object` anyway.This is called `type-erasure`.And you are adding your specific objects to the `Object` array which is legal – Cratylus Aug 18 '12 at 17:13
  • @Dims It will cause a `ClassCastException` only if you try to assign it to the reified type of `T`: `String[] foo = foo(); public static T[] foo() { return (T[]) new Object[5]; }` – Jeffrey Aug 18 '12 at 17:20
  • @Jeffrey @user384796 I have tried and it caused `ClassCastException`. I need to create normal array of normal type. – Dims Aug 18 '12 at 17:28