下面是如何使用泛型来获得一个正在寻找的类型的数组,同时保留类型安全性(与其他答案相反,后者将返回一个Object数组或在编译时导致警告):import java.lang.reflect.Array; public class GenSet {
private E[] a;
public GenSet(Class clazz, int length) {
a = clazz.cast(Array.newInstance(clazz.getComponentType(), length));
}
public static void main(String[] args) {
GenSet foo = new GenSet(String[].class, 1);
String[] bar = foo.a;
foo.a[0] = "xyzzy";
String baz = foo.a[0];
} }
在没有警告的情况下进行编译,正如您所看到的main,对于您声明GenSetas 的实例的任何类型,您可以分配a给该类型的数组,并且可以将元素分配给a该类型的变量,这意味着该数组并且数组中的值具有正确的类型。
它的工作原理是使用类文字作为运行时类型标记,如Java教程中所述。编译器将类文字视为实例java.lang.Class。要使用一个,只需按照类的名称.class。因此,String.class充当Class表示类的对象String。这也适用于接口,枚举,任何维数组(例如String[].class),基元(例如int.class)和关键字void(即void.class)。
Class本身是通用的(声明为Class,T代表Class对象所代表的类型),意味着类型String.class是Class。
因此,无论何时调用构造函数,都会GenSet为第一个参数传递一个类文字,表示GenSet实例声明类型的数组(例如String[].classfor GenSet)。请注意,您将无法获取基元数组,因为基元不能用于类型变量。
在构造函数内部,调用该方法cast将传递的Object参数强制转换为由调用该方法的Class对象表示的类。调用静态方法newInstance在java.lang.reflect.Array返回作为Object由所表示的类型的数组Class作为第一个参数,并通过指定的长度的传递的对象int通过作为第二个参数。调用该方法getComponentType返回一个Class表示组件类型由所表示的所述阵列的物体Class在其上的方法被调用(例如对象String.class为String[].class,null如果Class对象不表示阵列)。
最后一句话并不完全准确。调用String[].class.getComponentType()返回一个Class表示该类的对象String,但它的类型Class>不是Class,这就是为什么你不能做以下的事情。String foo = String[].class.getComponentType().cast("bar"); // won't compile
Class返回Class对象的每个方法都是如此。
关于Joachim Sauer对此答案的评论(我自己没有足够的声誉对其进行评论),使用强制转换的示例T[]将导致警告,因为在这种情况下编译器无法保证类型安全。
关于Ingo的评论编辑:public static T[] newArray(Class type, int size) {
return type.cast(Array.newInstance(type.getComponentType(), size));}