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
...
也根据我的知识.class文件不存储正式参数。那么如何使用反射?
请参阅Parameter.getName()
的Javadoc:
... 如果存在参数的名称,则此方法返回类文件提供的名称。否则,此方法综合了表单argn 的名称,其中n是声明参数的方法中参数的索引。
。
JDK是否支持这一点,是特定于实现的(您可以看到上述输出,JDK 8的构建125不支持它)。类文件格式支持可选属性,这些属性可以由特定的JVM/JAVAC实现可以使用,并被其他不支持它的实现所忽略。
请注意,您甚至可以使用arg0
,arg1
,...使用PRE JAVA 8 JVMS生成上述输出 - 您需要知道的是可以通过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);
}
}
JDK 8的新功能是,有一个扩展的API和可能性 jvms提供真实参数名称而不是arg0
,arg1
,...
可以通过可选属性来支持这种可选功能,可以将其附加到各种类文件结构上。参见4.6。类文件中method_info
结构的方法。另请参见4.7.1。在JVM规格中定义和命名新属性
由于使用JDK 8,类文件版本将增加到52,也可以更改文件格式以支持此功能。
另请参见JEP 118:在运行时访问参数名称,以获取更多信息和实现替代方案。提出的实现模型是添加一个可选的属性,该属性存储参数名称。由于类文件格式已经支持这些可选属性,因此甚至可以以某种方式可以使用旧的JVM来使用类文件,在该类别中,它们只是按照规格所要求的:
忽略了它们。Java虚拟机实现需要默默地忽略他们不认识的属性。
update
正如@Assylias所建议的那样,需要使用javac
命令行选项-parameters
编译源,以将参数名称反射的元数据添加到类文件中。但是,这当然只会影响使用此选项编译的代码 - 上面的代码仍将打印arg0
,arg1
等。由于运行时库未与此标志一起编译,因此不包含类文件中的必要条目。<<<<<<<<<<<<<<<<<<<<<<<<<</p>
谢谢Andreas,但最后我从Oracle教程中获得了有关方法参数的完整解决方案
它说,
您可以获取任何方法的形式参数的名称或使用该方法的构造函数java.lang.reflect.executable.getParameters。(类方法和构造函数扩展了类可执行文件,因此继承了方法可执行文件。默认情况下,正式参数名称。这是因为许多工具生产和消费类文件可能不会期望较大的静态和包含参数名称的.class文件的动态足迹。在特别是,这些工具必须处理较大的.class文件,并且Java虚拟机(JVM)将使用更多内存。此外,一些参数名称,例如秘密或密码,可能会暴露有关安全敏感方法的信息。
将正式参数名称存储在特定的.class文件中,因此使反射API能够检索正式参数名称,编译带有-Parameters选项的源文件Javac编译器。
如何编译
Remember to compile the with the -parameters compiler option
预期输出(有关完整的示例,请访问上述链接)
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
根据商店的信息,有关方法参数的信息(可通过反射可用),在Intellij 13中,Eclipse IDE中的" Javac -Parameters"等效的等效物是'商店'商店信息(可通过反思可通过反射))'在窗口中 ->首选项 -> java->编译器。
您可以使用Paranamer lib(https://github.com/paul-hammant/paranamer)
对我有用的示例代码:
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);
如果使用Maven,则将此依赖性放在您的pom.xml中:
<dependency>
<groupId>com.thoughtworks.paranamer</groupId>
<artifactId>paranamer</artifactId>
<version>2.8</version>
</dependency>