如何使用反射在 Java 8 中获取方法参数名称?
声明:本页面是StackOverFlow热门问题的中英对照翻译,遵循CC BY-SA 4.0协议,如果您需要使用它,必须同样遵循CC BY-SA许可,注明原文地址和作者信息,同时你必须将它归于原作者(不是我):StackOverFlow
原文地址: http://stackoverflow.com/questions/21455403/
Warning: these are provided under cc-by-sa 4.0 license. You are free to use/share it, But you must attribute it to the original authors (not me):
StackOverFlow
How to get Method Parameter names in Java 8 using reflection?
提问by Prateek
Java 8 has the ability to acquire method parameter names using Reflection API.
Java 8 能够使用反射 API 获取方法参数名称。
How can I get these method parameter names?
As per my knowledge, class files do not store formal parameter names. How can I get these using reflection?
如何获取这些方法参数名称?
据我所知,类文件不存储形式参数名称。如何使用反射获得这些?
回答by Andreas Fester
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 aMethod
by callinggetDeclaredMethod()
orgetDeclaredMethods()
which returns references toMethod
objects - From the
Method
object, call (new as of Java 8)getParameters()
which returns an array ofParameter
objects - On the
Parameter
object, callgetName()
- 获得对 a 的引用
Class
- 从
Class
,Method
通过调用getDeclaredMethod()
或getDeclaredMethods()
返回对Method
对象的引用来获取对 a的引用 - 从
Method
对象中调用(Java 8 中的新方法)getParameters()
,它返回一个Parameter
对象数组 - 在
Parameter
对象上,调用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?
另外据我所知 .class 文件不存储形式参数。那我怎样才能使用反射得到它们呢?
See the javadoc for Parameter.getName()
:
请参阅 javadoc 了解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.
...如果存在参数名称,则此方法返回类文件提供的名称。否则,此方法合成一个 argN 形式的名称,其中 N 是参数在声明参数的方法的描述符中的索引。
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.
JDK 是否支持这一点,是特定于实现的(正如您从上面的输出中看到的,JDK 8 的 build 125 不支持它)。类文件格式支持可选属性,这些属性可以由特定的 JVM/javac 实现使用,并且会被不支持它的其他实现忽略。
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()
:
请注意,您甚至可以使用arg0
, arg1
, ... 使用 Java 8 之前的 JVM生成上述输出- 您只需要知道可通过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 possibilityfor JVMs to provide the real parameter namesinstead of arg0
, arg1
, ...
什么是新的与JDK 8是,有一个扩展API和可能性为JVM中提供真正的参数名称代替arg0
,arg1
...
Supporting such optional features is possible through optional attributeswhich can be attached to the various class file structures. See 4.6. Methodsfor the method_info
structure within a class file. See also 4.7.1. Defining and Naming New Attributesin the JVM spec.
通过可以附加到各种类文件结构的可选属性,可以支持此类可选功能。见4.6。方法为method_info
一个类文件内的结构。另见4.7.1。在 JVM 规范中定义和命名新属性。
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.
由于使用 JDK 8,类文件版本将增加到 52,因此也可以更改文件格式本身以支持此功能。
See also JEP 118: Access to Parameter Names at Runtimefor 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:
另请参阅JEP 118:在运行时访问参数名称以获取更多信息和实现替代方案。建议的实现模型是添加一个存储参数名称的可选属性。由于类文件格式已经支持这些可选属性,这甚至可以以某种方式实现,以便旧的 JVM 仍然可以使用类文件,而根据规范的要求,它们会被简单地忽略:
Java Virtual Machine implementations are required to silently ignore attributes they do not recognize.
Java 虚拟机实现需要静默忽略它们无法识别的属性。
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.
正如@assylias 所建议的,需要使用javac
命令行选项编译源代码-parameters
,以便将参数名称反射的元数据添加到类文件中。然而,这当然只会影响用这个选项编译的代码——上面的代码仍然会打印arg0
,arg1
等等,因为运行时库不是用这个标志编译的,因此在类文件中不包含必要的条目。
回答by Prateek
Thanks Andreas, but finally i got the complete solution from oracle Tutorials on Method Parameters
谢谢 Andreas,但最后我从 oracle Tutorials on Method Parameters得到了完整的解决方案
It says,
它说,
You can obtain the names of the formal parameters of any method or constructor with the method java.lang.reflect.Executable.getParameters. (The classes Method and Constructor extend the class Executable and therefore inherit the method Executable.getParameters.) However, .class files do not store formal parameter names by default. This is because many tools that produce and consume class files may not expect the larger static and dynamic footprint of .class files that contain parameter names. In particular, these tools would have to handle larger .class files, and the Java Virtual Machine (JVM) would use more memory. In addition, some parameter names, such as secret or password, may expose information about security-sensitive methods.
To store formal parameter names in a particular .class file, and thus enable the Reflection API to retrieve formal parameter names, compile the source file with the -parameters option to the javac compiler.
您可以使用 java.lang.reflect.Executable.getParameters 方法获取任何方法或构造函数的形参名称。(Method 和 Constructor 类扩展了 Executable 类,因此继承了 Executable.getParameters 方法。)但是,默认情况下 .class 文件不存储形式参数名称。这是因为许多生成和使用类文件的工具可能不希望包含参数名称的 .class 文件有更大的静态和动态占用空间。特别是,这些工具必须处理更大的 .class 文件,而 Java 虚拟机 (JVM) 将使用更多内存。此外,某些参数名称,例如机密或密码,可能会暴露有关安全敏感方法的信息。
要将形式参数名称存储在特定的 .class 文件中,从而使反射 API 能够检索形式参数名称,请使用 -parameters 选项将源文件编译为 javac 编译器。
How to Compile
如何编译
Remember to compile the with the -parameters compiler option
Remember to compile the with the -parameters compiler option
Expected Output(For complete example visit the link mentioned above)
预期输出(有关完整示例,请访问上面提到的链接)
java MethodParameterSpy ExampleMethods
java MethodParameterSpy ExampleMethods
This command prints the following:
此命令打印以下内容:
Number of constructors: 1
Constructor #1
public ExampleMethods()
Number of declared constructors: 1
Declared constructor #1
public ExampleMethods()
Number of methods: 4
Method #1
public boolean ExampleMethods.simpleMethod(java.lang.String,int)
Return type: boolean
Generic return type: boolean
Parameter class: class java.lang.String
Parameter name: stringParam
Modifiers: 0
Is implicit?: false
Is name present?: true
Is synthetic?: false
Parameter class: int
Parameter name: intParam
Modifiers: 0
Is implicit?: false
Is name present?: true
Is synthetic?: false
Method #2
public int ExampleMethods.varArgsMethod(java.lang.String...)
Return type: int
Generic return type: int
Parameter class: class [Ljava.lang.String;
Parameter name: manyStrings
Modifiers: 0
Is implicit?: false
Is name present?: true
Is synthetic?: false
Method #3
public boolean ExampleMethods.methodWithList(java.util.List<java.lang.String>)
Return type: boolean
Generic return type: boolean
Parameter class: interface java.util.List
Parameter name: listParam
Modifiers: 0
Is implicit?: false
Is name present?: true
Is synthetic?: false
Method #4
public <T> void ExampleMethods.genericMethod(T[],java.util.Collection<T>)
Return type: void
Generic return type: void
Parameter class: class [Ljava.lang.Object;
Parameter name: a
Modifiers: 0
Is implicit?: false
Is name present?: true
Is synthetic?: false
Parameter class: interface java.util.Collection
Parameter name: c
Modifiers: 0
Is implicit?: false
Is name present?: true
Is synthetic?: false
回答by vorburger
as per Store information about method parameters (usable via reflection) in intellij 13, the equivalent of "javac -parameters" within the Eclipse IDE is 'Store information about method parameters (usable via reflection)' in Window -> Preferences -> Java -> Compiler.
根据intellij 13 中有关方法参数的存储信息(可通过反射使用),Eclipse IDE 中“javac -parameters”的等价物是窗口 -> 首选项 -> Java 中的“存储有关方法参数的信息(可通过反射使用)” - > 编译器。
回答by Gustavo Leit?o
You can use Paranamer lib (https://github.com/paul-hammant/paranamer)
您可以使用 Paranamer 库(https://github.com/paul-hammant/paranamer)
Sample code that works for me:
对我有用的示例代码:
import com.thoughtworks.paranamer.AnnotationParanamer;
import com.thoughtworks.paranamer.BytecodeReadingParanamer;
import com.thoughtworks.paranamer.CachingParanamer;
import com.thoughtworks.paranamer.Paranamer;
Paranamer info = new CachingParanamer(new AnnotationParanamer(new BytecodeReadingParanamer()));
Method method = Foo.class.getMethod(...);
String[] parameterNames = info.lookupParameterNames(method);
If you use Maven then put this dependency in your pom.xml:
如果您使用 Maven,则将此依赖项放在您的 pom.xml 中:
<dependency>
<groupId>com.thoughtworks.paranamer</groupId>
<artifactId>paranamer</artifactId>
<version>2.8</version>
</dependency>