关于java:从`String.class`得到`String [] .class`,如果`String.class`是"运行时类型"怎么办?

wat*_*erg 31 java arrays reflection runtime class

这是一个变量Class<?> cls,现在我想得到另一个Array Class Object组件类型cls.

例如,如果cls= String.class,我想得到String[].class; if cls= int.class,我想知道int[].class,我该怎么办?

你看,这是很容易得到String.class来自String[].class:

Class<?> arrayCls = String[].class;
if(arrayCls.isArray()){
    Class<?> cls = arrayCls.getComponentType();
}
Run Code Online (Sandbox Code Playgroud)

但我找不到简单的方法来做相反的事情.

这是一个可能的解决方案:

Class<?> clazz = String.class;
Class<?> arrayClass = Array.newInstance(clazz,0).getClass();
Run Code Online (Sandbox Code Playgroud)

请问有什么打击方法吗?

Lim*_*eth 16

HRgiger的答案有所改善:

@SuppressWarnings("unchecked")
static <T> Class<? extends T[]> getArrayClass(Class<T> clazz) {
    return (Class<? extends T[]>) Array.newInstance(clazz, 0).getClass();
}
Run Code Online (Sandbox Code Playgroud)

它们都在调用时实例化一个数组对象.要获取阵列类型,请使用

Class<?> childType = ...;
Class<?> arrayType = getArrayClass(childType);
Run Code Online (Sandbox Code Playgroud)


HRg*_*ger 10

我发现的另一个技巧是在util方法上使用varargs.

public static void main(String[] args) throws ClassNotFoundException {

    Class<?> demo = Main.<String>getArrayClass();
    System.out.println(demo);
}

static <T> Class getArrayClass(T... param){
    return param.getClass();
}
Run Code Online (Sandbox Code Playgroud)

  • 非常好的技巧.但它对OP没有帮助,因为你需要在编译时知道这个类.如果你在编译时知道它是`String`,你可以说`String [] .class`. (8认同)
  • 为什么不会因为运行时类型擦除而每次返回`Object []`的类? (5认同)
  • @SpaceTrucker,这是一个迟到的响应,但在调查之后看起来类型擦除似乎不适用于此处,因为varargs参数类型在编译时已知为方法调用.如果我们不知道参数类型(例如,`<U> void otherMethod(U obj){System.out.println(getArrayClass(obj));}`)那么类型擦除将适用并且`T ... param `将始终是一个`Object []`,在这种情况下,将始终返回`Object [] .class`. (2认同)

zie*_*ikk 9

也许试试Class.forName(String)

编辑:这是一个代码段.

Class<?> arrayClass = String[].class;
System.out.println(arrayClass);
Class<?> namedClass = Class.forName("[L" + String.class.getName() + ";");
System.out.println(namedClass);
System.out.println(arrayClass == namedClass);
Run Code Online (Sandbox Code Playgroud)

  • @Kidburla:命名[不仅仅是一个约定](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html#getName--).尽管如此,创建一个零大小的数组比字符串连接更便宜,更不用说之后在`Class.forName`中执行的动态类查找.如果你有一个任意的`Class`对象,`Class.forName("[L"+ clazz.getName()+";");`如果`clazz`表示基本类型或数组类型,`将失败,所以底线是,`Array.newInstance(clazz,0).getClass()`是*更好的方式* (9认同)
  • 我个人更喜欢使用`Array.newInstance`的解决方案.这至少使用了记录的功能.但名称前缀`[L`是一个内部约定.将来他们可以改变它并改变`XMLEncoder`类,因为它也是JDK的一部分.仅仅因为某些东西在JDK中以某种方式做某事,并不意味着你应该这样做,因为你正在编写应用程序代码而不是JDK代码. (3认同)