Java 8具有使用反射API获取方法参数名称的功能。
我该如何获取这些方法参数名称?
据我所知,类文件不存储形式参数名称。 我该如何使用反射获取这些名称?
Java 8具有使用反射API获取方法参数名称的功能。
我该如何获取这些方法参数名称?
据我所知,类文件不存储形式参数名称。 我该如何使用反射获取这些名称?
如何获取这些方法参数的名称?
基本上,你需要:
Class
的引用Class
中通过调用 getDeclaredMethod()
或 getDeclaredMethods()
获取对 Method
的引用,它们返回对 Method
对象的引用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());
}
}
输出:
...
indexOf
arg0
indexOf
arg0
arg1
...
Parameter.getName()
的Javadoc:Method.getParameterTypes()
访问的参数计数来生成上述输出:arg0
,arg1
等。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);
}
}
Java虚拟机实现需要默默地忽略它们不认识的属性。
更新
如@assylias所建议,源代码需要使用javac
命令行选项-parameters
编译,以便向类文件添加参数名称反射的元数据。但是,这当然只会影响使用此选项编译的代码 - 上面的代码仍将打印arg0
,arg1
等,因为运行时库未使用此标志进行编译,因此不包含类文件中必要的条目。
感谢Andreas,但是我最终从Oracle教程中获得了完整的解决方案,链接为Method Parameters
它说:
您可以使用方法java.lang.reflect.Executable.getParameters获取任何方法或构造函数的形式参数的名称。 (类Method和Constructor扩展了类Executable,因此继承了方法Executable.getParameters。)但是,默认情况下,.class文件不存储形式参数名称。这是因为许多生成和消耗类文件的工具可能不希望期望包含参数名称的更大的静态和动态占用空间的.class文件。特别是,这些工具将必须处理较大的.class文件,并且Java虚拟机(JVM)将使用更多内存。此外,某些参数名称(例如secret或password)可能会暴露有关安全敏感方法的信息。
要在特定的.class文件中存储形式参数名称,从而使Reflection API检索形式参数名称,请使用-parameters选项将源文件编译为javac编译器。
请记住使用-parameters编译器选项进行编译
java MethodParameterSpy ExampleMethods
此命令将打印以下内容:
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
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);
<dependency>
<groupId>com.thoughtworks.paranamer</groupId>
<artifactId>paranamer</artifactId>
<version>2.8</version>
</dependency>