在。NET,我可以这样做:
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;
}
我们必须指定“where T : new()”子句。
如何在 Java 中做到这一点?
除非您将 T 作为参数传递,否则您将无法在 java 中创建泛型“T”类型的数组。
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;
}
Java 没有等效的构造。包含构造函数的类没有编译时安全性。
您可以在运行时执行此操作,但您必须传递非空 T 或 Class 作为参数。实际使用的类型参数不会在运行时保留。
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;
}
如果没有公共无参数构造函数,上述方法将起作用,但会引发异常。您无法让编译器强制执行存在一个。
编辑:ChssPly76 击败了我,所以我修改了上面的代码以给出一个示例,您可以在其中传递一个实际的对象样本,只是为了展示它是如何完成的。通常在这种情况下,您会传入类,因为 sampleObject 不会最终出现在数组中。
在 Java 中,不能实例化泛型数组。(例如 new T[size] 不能工作)这是因为在运行时泛型类型会丢失(“擦除”)并且无法恢复。
是否有不能使用的原因,例如 new ArrayList<T>()?
您可以使用此想法来解决其他答案中缺少编译时间检查的问题:
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");
}
}
这实际上比您描述的 C# 方式更灵活,因为您可以根据需要控制构造函数,而不是简单地调用无参数的构造函数。
您不能在 Java 中执行此操作,因为 Java 不支持结构类型检查。
Scala 可以,但它比实现适当的接口要慢得多(因为它在内部使用反射来进行函数调用)。Scala 不允许您对对象构造函数的形式设置约束。JVM 使用类型擦除,因此通用代码实际上并不知道它在操作什么类型,因此它无论如何也无法构造该类型的新对象。