views:

174

answers:

5

In. NET, I can do something like this:

public static T[] CreateAndFillArray<T>(int size) where T : new()
{
   T[] array = new T[size];
   for (int i = size - 1; i >= 0; i--)
       array[i] = new T();
   return array;
}

We must to specify "where T : new()" clause.

How to do it in Java?

+10  A: 

You will not be able to create an array of generic "T" type in java unless you pass in T as parameter.

public static <T> T[] createAndFillArray(Class<T> cls, int size) {
  T[] result = (T[]) Array.newInstance(cls, size);
  for (int i=0; i<size; i++) {
    result[i] = cls.newInstance();
  }
  return result;
}
ChssPly76
Correct. Unlike C#, Java doesn't have reified generics. So the actual type of `T` isn't available for use in constructing new objects.
Daniel Pryden
It's interesting to note that CLR actually does a very similar trick to do `new T()` (and `typeof(T)`, and a few other similar things where it really must know `T`) - it adds a hidden method parameter for the type handle under the hood. The only difference is that it's not visible either on C# nor on IL level - it's an implementation detail of the runtime.
Pavel Minaev
+3  A: 

In Java, you cannot instantiate a generic array. (e.g. new T[size] can not work) This is because at runtime the types of generics are lost ("erasure") and cannot be recovered.

Is there a reason you can not use, for example, new ArrayList<T>()?

Steven Schlansker
Of course, I can use ArrayList. I wanted to know if I can do so in Java ;)
mykhaylo
@mykhaylo: Huh? `ArrayList` *is* part of Java. And `ArrayList` won't solve all your problems, unless you change your function to accept an `ArrayList` as a parameter. Just like you can't do `new T[size]`, you can't do `new ArrayList<T>()` either, since `T` is actually erased at runtime.
Daniel Pryden
@Daniel - you **can** do `new ArrayList<T>()`; you just can't populate it with new instances of T without passing `Class<T>` as parameter.
ChssPly76
It won't solve his problems, because there's still no analog to `new T()`. He can create an `ArrayList`, sure, but he can't fill it with instances.
Pavel Minaev
+3  A: 

Java does not have an equivalent construct. There is no compile time safety on a class containing a constructor.

You can do it at runtime, but you have to either pass a non-null T or a Class as a parameter. The actual type parameter used is not retained at runtime.

public static <T> T[] createAndFillArray(T sampleObject, int size) throws Exception {
        Class<T> klass = sampleObject.getClass();
        T[] arr = (T[]) Array.newInstance(klass, size);
        for (int i = 0; i < size; i++) {
            arr[i] = klass.newInstance();
        }
        return arr;
}

The above will work but throw an exception if there is no public no argument constructor. You cannot get the compiler to enforce that there is one.

Edit: ChssPly76 beat me to it, so I modified the above code to give an example where you pass in an actual object sample, just to show how it is done. Normally in such a case you would pass in the class because the sampleObject doesn't end up in the array.

Yishai
A: 

You cannot do this in Java, because Java does not support structural type checks.

Scala does, but it's a lot slower than implementing an appropriate interface (since it uses reflection internally to make the function calls). Scala doesn't let you set constraints on the form of the object's constructor. The JVM uses type erasure, so the generic code doesn't actually know what type it's operating on, so it can't construct new objects of that type anyway.

Ken Bloom
+1  A: 

You can use this idea to fix the lack of compile time checking in the other answers:

import java.lang.reflect.Array;

public class Main
{
    public static void main(String[] args)
    {
        final String[] array;

        array = createAndFillArray(String.class, 10, new StringCreator());

        for(final String s : array)
        {
            System.out.println(s);
        }
    }

    public static <T> T[] createAndFillArray(final Class<T>   clazz,
                                             final int        size,
                                             final Creator<T> creator)
    {
        T[] result = (T[]) Array.newInstance(clazz, size);

        for (int i=0; i<size; i++)
        {
            result[i] = creator.newInstance();
        }

        return result;
    }
}

interface Creator<T>
{
    T newInstance();
}

class StringCreator
    implements Creator<String>
{
    public String newInstance()
    {
        // not the best example since String is immutable but you get the idea
        // you could even have newInstance take an int which is the index of the 
        // item being created if that could be useful (which it might).
        return ("hello");
    }
}

This is actually more flexible than the C# way you describe since you can control the constructor if you want rather than simply calling the no-arg one.

TofuBeer