关于java:从`String.class`获取`String[].class`,如果`String.class`是“运行时类型”怎么办? [复制]

Posted

技术标签:

【中文标题】关于java:从`String.class`获取`String[].class`,如果`String.class`是“运行时类型”怎么办? [复制]【英文标题】:about java: get `String[].class` from `String.class`, what if `String.class` is a "runtime type"? [duplicate] 【发布时间】:2012-11-03 17:40:24 【问题描述】:

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

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

你看,从String[].class得到String.class很容易:

Class<?> arrayCls = String[].class;
if(arrayCls.isArray())
    Class<?> cls = arrayCls.getComponentType();

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

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

Class<?> clazz = String.class;
Class<?> arrayClass = Array.newInstance(clazz,0).getClass();

请问有什么方法可以做到这一点吗?

【问题讨论】:

那个解决方案有什么问题? @Thilo 该解决方案是我猜测的结果。它工作正常,但我不确定这是否是最好的方法。该方案需要动态创建一个长度为0的数组实体。 有趣的问题。只是好奇为什么需要数组Class 对象? Array.newInstance(clazz,0) 在操作数堆栈上创建一个短期对象,JIT 可能会优化它,但我不会指望它。 【参考方案1】:

HRgiger 的回答有所改进:

@SuppressWarnings("unchecked")
static <T> Class<? extends T[]> getArrayClass(Class<T> clazz) 
    return (Class<? extends T[]>) Array.newInstance(clazz, 0).getClass();

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

Class<?> childType = ...;
Class<?> arrayType = getArrayClass(childType);

【讨论】:

这与HRgiger的回答无关,这是对OP在问题中发布的内容的改进。 另外,我很确定你每次都在这里实例化一个新对象,而另一个答案不是。 请注意,如果您将原始类型传递给此未经检查的强制转换,则会被破坏。例如,int.classClass&lt;Integer&gt;,但 int[].classClass&lt;int[]&gt;,而不是 Class&lt;Integer[]&gt;。该方法应该只返回一个Class&lt;?&gt;,或者它应该检查是否clazz.isPrimitive(),如果是则抛出异常。 为什么是&lt;? extends T[]&gt;?我理解为什么getClass() 通常会返回它,但是在这种情况下,我们知道数组具有确切的类型T[](假设 clazz 不是原始的,但无论如何都会破坏这一点),所以只要我们是无论如何都要进行未经检查的演员表,为什么不更精确呢?【参考方案2】:

我发现的另一个技巧是在 util 方法上使用可变参数。

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();

【讨论】:

不错的技巧 +1 实际上,如果您在调用站点指定T,则无需传递任何参数:MyClass.&lt;String&gt;getArrayClass(); 为什么不会因为运行时类型擦除而每次都返回Object[]的类? 非常好的技巧。但它对 OP 没有帮助,因为您需要在编译时了解该类。如果你在编译时知道它是String,你可以直接说String[].class @SpaceTrucker,Saintali 对,我没有花太多时间,因为已经有了解决方案,只是想分享一下,也许类似的情况可能是个不错的选择:) @SpaceTrucker,这是一个较晚的响应,但经过调查后,类型擦除似乎不适用于此处,因为在编译时方法调用的 varargs 参数类型是已知的。如果我们不知道参数类型(例如,&lt;U&gt; void otherMethod(U obj) System.out.println(getArrayClass(obj)); ),则类型擦除将适用,T... param 将始终是 Object[],在这种情况下,Object[].class 将始终返回。【参考方案3】:

也许试试Class.forName(String)

编辑:这是一个代码 sn-p。

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);

【讨论】:

根据 jdk 中的 XMLEncoder 类,Class.forName(String) 是执行此操作的标准方法。多谢,伙计。 Class&lt;?&gt; cls=String.class; Class&lt;?&gt; arrayCls=Class.forName("[L"+cls.getName()+";");***.com/questions/4581394/… 啊。我忘了最后的分号。 我个人更喜欢使用Array.newInstance 的解决方案。这至少使用了记录的功能。但是名称前缀[L 是内部约定。将来他们可以更改它并更改 XMLEncoder 类,因为这也是 JDK 的一部分。仅仅因为某些东西在 JDK 中以某种方式做某事,并不意味着你应该这样做,因为你正在编写应用程序代码而不是 JDK 代码。 @Kidburla:命名is more than a convention。尽管如此,创建一个大小为零的数组还是比字符串连接便宜得多,更不用说之后在Class.forName 中执行的动态类查找了。如果你有一个任意的Class 对象,如果clazz 表示原始类型或数组类型,Class.forName("[L"+clazz.getName()+";"); 将失败,所以底线是,Array.newInstance(clazz,0).getClass() 更好跨度> @Holger 应该写一个答案。你是 100000% 正确的。 OP 甚至提到了原语的要求和动态性质的要求(后面在 cmets 中提到)。就好像 OP 没有根据他们指定的要求测试他们的代码。我知道这个问题很老,但你可能会在一段时间内通过当前接受的答案,而且它更能内省手头的情况。

以上是关于关于java:从`String.class`获取`String[].class`,如果`String.class`是“运行时类型”怎么办? [复制]的主要内容,如果未能解决你的问题,请参考以下文章

Java Class类以及获取Class实例的三种方式

Java 反射理解-- Java获取方法信息

java中 .class 属性从哪里来?哪个类中的属性?

java中int.Class和String.Class指啥,麻烦谁能详细解释一下。

String class fetch functionality

Java泛型相关