如何使用反射在 Java 8 中获取方法参数名称? [英] How to get Method Parameter names in Java 8 using reflection?

查看:64
本文介绍了如何使用反射在 Java 8 中获取方法参数名称?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

Java 8 能够使用反射 API 获取方法参数名称.

  1. 如何获取这些方法参数名称?

  2. 据我所知,类文件不存储形式参数名称.如何使用反射获得这些?

解决方案

如何获取这些方法参数名称?

基本上,您需要:

  • 获取对Class
  • 的引用
  • Class,通过调用 getDeclaredMethod()getDeclaredMethods() 返回对 Method 对象的引用
  • Method 对象,调用(Java 8 的新功能)getParameters(),它返回一个 Parameter 对象数组
  • Parameter对象上,调用getName()

Classclz = String.class;for (方法 m : clz.getDeclaredMethods()) {System.err.println(m.getName());for (参数 p : m.getParameters()) {System.err.println(" " + p.getName());}}

输出:

<代码>...指数参数0指数参数0参数1...

<小时><块引用>

此外,据我所知,.class 文件不存储形式参数.那么我怎样才能使用反射得到它们呢?

请参阅的javadocParameter.getName():

<块引用>

... 如果参数名称存在,则此方法返回类文件提供的名称.否则,这个方法合成一个形式为argN的名字,其中N是参数在声明参数的方法的描述符中的索引.

JDK 是否支持这一点,是特定于实现的(从上面的输出中可以看出,JDK 8 的 build 125 不支持它).类文件格式支持可选属性,这些属性可以由特定的 JVM/javac 实现使用,并且会被不支持它的其他实现忽略.

请注意,您甚至可以使用 arg0arg1、... 使用 Java 8 之前的 JVM 生成上述输出 - 您只需要知道其中的参数计数可通过 Method.getParameterTypes() 访问:

Classclz = String.class;for (方法 m : clz.getDeclaredMethods()) {System.err.println(m.getName());int paramCount = m.getParameterTypes().length;for (int i = 0; i < paramCount; i++) {System.err.println("arg" + i);}}

JDK 8 的新特性是有一个扩展的 API 和可能性让 JVM 提供实际参数名称而不是arg0, arg1, ...

通过可以附加到各种类文件结构的可选属性来支持这些可选功能是可能的.请参阅 4.6.类文件中 method_info 结构的方法.另请参阅 4.7.1.在 JVM 规范中定义和命名新属性.

从 JDK 8 开始,类文件版本将增加到 52,也可以更改文件格式本身以支持此功能.

另请参阅JEP 118:在运行时访问参数名称,了解更多信息和实现替代方案.建议的实现模型是添加一个存储参数名称的可选属性.由于类文件格式已经支持这些可选属性,这甚至可以以某种方式实现,以便旧的 JVM 仍然可以使用类文件,而根据规范的要求,它们会被简单地忽略:

<块引用>

Java 虚拟机实现需要静默忽略它们无法识别的属性.

更新

正如@assylias 所建议的,需要使用javac 命令行选项-parameters 编译源代码,以便将参数名称反射的元数据添加到类文件.但是,这当然只会影响使用此选项编译的代码 - 上面的代码仍会打印 arg0arg1 等,因为运行时库未使用此标志编译因此在类文件中不包含必要的条目.

Java 8 has the ability to acquire method parameter names using Reflection API.

  1. How can I get these method parameter names?

  2. As per my knowledge, class files do not store formal parameter names. How can I get these using reflection?

解决方案

How can i get these method parameter names?

Basically, you need to:

  • get a reference to a Class
  • From the Class, get a reference to a Method by calling getDeclaredMethod() or getDeclaredMethods() which returns references to Method objects
  • From the Method object, call (new as of Java 8) getParameters() which returns an array of Parameter objects
  • On the Parameter object, call getName()

Class<String> clz = String.class;
for (Method m : clz.getDeclaredMethods()) {
   System.err.println(m.getName());
   for (Parameter p : m.getParameters()) {
      System.err.println("  " + p.getName());
   }
}

Output:

...
indexOf
  arg0
indexOf
  arg0
  arg1
...


Also as per my knowledge .class files do not store formal parameter. Then how can i get them using reflection?

See the javadoc for Parameter.getName():

... If the parameter's name is present, then this method returns the name provided by the class file. Otherwise, this method synthesizes a name of the form argN, where N is the index of the parameter in the descriptor of the method which declares the parameter.

Whether a JDK supports this, is implementation specific (as you can see form the above output, build 125 of JDK 8 does not support it). The class file format supports optional attributes which can be used by a specific JVM/javac implementation and which are ignored by other implementations which do not support it.

Note that you could even generate the above output with arg0, arg1, ... with pre Java 8 JVMs - all you need to know is the parameter count which is accessible through Method.getParameterTypes():

Class<String> clz = String.class;
for (Method m : clz.getDeclaredMethods()) {
  System.err.println(m.getName());
  int paramCount = m.getParameterTypes().length;
  for (int i = 0;  i < paramCount;  i++) {
    System.err.println("  arg" + i);
  }
}

What is new with JDK 8 is that there is an extended API and the possibility for JVMs to provide the real parameter names instead of arg0, arg1, ...

Supporting such optional features is possible through optional attributes which can be attached to the various class file structures. See 4.6. Methods for the method_info structure within a class file. See also 4.7.1. Defining and Naming New Attributes in the JVM spec.

Since with JDK 8, the class file version will be incremented to 52, it would also be possible to change the file format itself to support this feature.

See also JEP 118: Access to Parameter Names at Runtime for more information and implementation alternatives. The proposed implementation model is to add an optional attribute which stores the parameter names. Since the class file format already supports these optional attributes, this would even be possible in a way so that the class files can still be used by older JVMs, where they are simply ignored as demanded by the spec:

Java Virtual Machine implementations are required to silently ignore attributes they do not recognize.

Update

As suggested by @assylias, the source needs to be compiled with the javac command line option -parameters in order to add the meta data for parameter name reflection to the class file. However, this will of course only affect code compiled with this option - the code above will still print arg0, arg1 etc. since the runtime libraries are not be compiled with this flag and hence do not contain the necessary entries in the class files.

这篇关于如何使用反射在 Java 8 中获取方法参数名称?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆