如何在Java8中使用反射获取方法参数名?
Java8能够使用反射API获取方法参数名称如何在Java8中使用反射获取方法参数名?,java,reflection,java-8,method-parameters,Java,Reflection,Java 8,Method Parameters,Java8能够使用反射API获取方法参数名称 如何获取这些方法参数名 据我所知,类文件不存储正式的参数名。如何使用反射获取这些信息 如何获取这些方法参数名称? 基本上,您需要: 获取对类的引用 从类中,通过调用或getDeclaredMethods()获取对方法的引用,该方法返回对方法对象的引用 从方法对象中,调用(从Java 8开始新增)getParameters(),它返回一个参数对象数组 在参数对象上,调用getName() 据我所知,类文件不存储形式参数。那么,如何使用反射获取它们
- 获取对
类的引用
- 从
中,通过调用或类
获取对getDeclaredMethods()
的引用,该方法返回对方法
对象的引用方法
- 从
对象中,调用(从Java 8开始新增)方法
,它返回一个getParameters()
对象数组参数
- 在
对象上,调用参数
getName()
据我所知,类文件不存储形式参数。那么,如何使用反射获取它们? 请参阅javadoc以了解: 如果参数的名称存在,则此方法返回类文件提供的名称否则,此方法合成一个argN形式的名称,其中N是声明参数的方法描述符中参数的索引 JDK是否支持这一点取决于具体的实现(从上面的输出可以看出,JDK 8的build 125不支持它)。类文件格式支持可选属性,这些属性可由特定JVM/javac实现使用,其他不支持它的实现会忽略这些属性 请注意,您甚至可以使用
arg0
,arg1
。。。对于Java 8之前的JVM,您只需要知道参数计数,该计数可通过方法访问。getParameterTypes()
:
Class clz=String.Class;
对于(方法m:clz.getDeclaredMethods()){
System.err.println(m.getName());
int paramCount=m.getParameterTypes().length;
对于(int i=0;i
JDK 8的新功能是有一个扩展的API,JVM可以提供真实参数名,而不是arg0
,arg1
可以通过附加到各种类文件结构的可选属性来支持这些可选特性。有关类文件中的方法\u info
结构,请参阅。另请参见JVM规范中的
由于使用JDK 8,类文件版本将增加到52,因此也可以更改文件格式本身以支持此功能
有关更多信息和实现备选方案,请参见。建议的实现模型是添加一个可选属性来存储参数名。由于类文件格式已经支持这些可选属性,这在某种程度上甚至是可能的,以便旧JVM仍然可以使用这些类文件,而这些类文件只是根据规范的要求被忽略:
Java虚拟机实现需要以静默方式忽略它们无法识别的属性
更新
正如@assylias所建议的,需要使用
javac
命令行选项-parameters
编译源代码,以便将参数名称反射的元数据添加到类文件中。但是,这当然只会影响使用此选项编译的代码-上面的代码仍将打印arg0
,arg1
等。因为运行时库不使用此标志编译,因此在类文件中不包含必要的条目。谢谢Andreas,但最终我从oracle教程中获得了完整的解决方案
上面说,
您可以获取任何方法或方法的形式参数的名称
方法的构造函数
java.lang.reflect.Executable.getParameters。(类和方法)
构造函数扩展类的可执行文件,从而继承
但是,.class文件不存储
默认情况下,形式参数名。这是因为许多工具
生成和使用类文件可能不需要更大的静态和
包含参数名称的.class文件的动态示意图。在里面
特别是,这些工具必须处理更大的.class文件,以及
Java虚拟机(JVM)将使用更多内存。此外
某些参数名称(如secret或password)可能会暴露
有关安全敏感方法的信息
将正式参数名存储在特定的.class文件中,从而
使反射API能够检索正式参数名,并编译
javac编译器的带有-parameters选项的源文件
如何编译
记住使用-parameters编译器选项编译
预期输出(如需完整示例,请访问上述链接)
java方法参数间谍示例方法
此命令打印以下内容:
施工人员人数:1人
构造函数#1
公共示例方法()
声明的构造函数数:1
声明构造函数#1
公共示例方法()
方法数目:4
方法#1
公共布尔ExampleMethods.simpleMethod(java.lang.String,int)
返回类型:boolean
泛型返回类型:boolean
参数类:class java.lang.String
参数名称:stringParam
修改器:0
是隐式的吗?:假
有名字吗?:对
是人工合成的吗
参数类:int
参数名称:intParam
修改器:0
是隐式的吗?:假
有名字吗?:对
是人工合成的吗
方法#2
平民的
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<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);
}
}
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>