前言
大家都知道随着java8的使用,在相应的方法签名中增加了新的对象Parameter,用于表示特定的参数信息,通过它的getName可以获取相应的参数名.即像在代码中编写的,如命名为username,那么在前台进行传参时,即不需要再编写如@Parameter("username")类的注解,而直接就能进行按名映射.
如下的代码参考所示:
public class T { private interface T2 { void method(String username, String password); } public static void main(String[] args) throws Exception { System.out.println(T.class.getMethod("main", String[].class).getParameters()[0].getName()); System.out.println(T2.class.getMethod("method", String.class, String.class).getParameters()[0].getName()); System.out.println(T2.class.getMethod("method", String.class, String.class).getParameters()[1].getName()); } }
按java8之前,也可以通过一些手段拿到参数名信息,只不过方式不同而已.如通过spring mvc中的ParameterMethodNameResolver在之前的版本中也可以正常工作.不过需要特别的编译而已.这里面起作用的即是 LocalVariableTable 和 MethodParameters,中文编译为本地变量表和方法参数表.
LocalVariableTable 本地变量表
按jvm规范所述,本地变量表存在于Code属性中,而Code属性即又是methodInfo的一个属性.可以理解为,当一个方法有方法体时,就会出现相应的Code属性,而且在code属性中,除具体的执行代码外,还会有其它的信息.如LineNumberTable(用于描述每一行代码所在的位置).
本地变量表属于在方法中调试信息的一部分,因此默认情况下这些信息是不会生成在class文件当中的.需要开启 -g 或 -g:vars 开关.还好,对于ide或者是maven编译来说,这些开关都是默认开启的.在ide中,可以通过设置(generate debugging info 针对idea)来控制(默认打勾).在maven中,通过通过插件 maven-compiler-plugin 中的debug或debugLevel来控制是否输出(默认值是true).
本地变量表在javap之后,如下所示:
//非静态方法 LocalVariableTable: Start Length Slot Name Signature 0 1 0 this LT; 0 1 1 count J 0 1 3 name Ljava/lang/String; //静态方法 LocalVariableTable: Start Length Slot Name Signature 0 101 0 args [Ljava/lang/String;
本地变量表不仅保存了参数信息,还保存在在整个方法体中可能会使用的临时变量,如声明的int i等.并且如上所示,表示方法和非静态方法,在第一位还有this变量的区别.因此,可以通过读取参数个数(method.getParameterCount),然后再根据方法签名,读取本地变量表中指定个数的参数信息即可.
需要注意的是,在上图中,如果参数为long或double,其slot占位为2个,在通过slot来获取参数信息时,需要考虑参数的类型信息.
接口方法由于没有code属性,因此也没有本地变量表,拿到一个接口的方法定义,通过本地变量表是不能获取到相应的参数名的
MethodParameters 方法参数表
方法参数表是在1.8之后引入的,因此只是使用jdk8编译生成的class文件才有此信息. 与本地变量表不同,它是属于MethodInfo属性的,即它是与Code属性同一级别的.不管是接口方法还是普通的方法,都是有此属性的.因此,即使是接口方法,也可以获取相应的参数信息.
默认情况下,class中是没有此信息的.需要使用特殊的编译参数 -parameters 才能生成,并且在ide和maven中,也默认不会生成此信息.在idea中,需要在java additional line parameters中增加此编译参数.在maven中,也需要在maven-compiler-plugin的compilerArgs参数中增加此参数才行.
方法参数表在javap之后,表现为如下形式:
//非静态方法 MethodParameters: Name Flags count name //静态方法 MethodParameters: Name Flags args
可以看出,无论是否静态,在参数表中,只会出现用于描述参数的信息.后面的Flags参数用于一些特殊的场景,比如final参数用于方法改写等.
可使用的一些工具
除使用原生的api,以及spring工具包,还有其它一些工具都可以拿到参数名信息.在spring体系中,用于描述参数名的接口为 ParameterNameDiscoverer.通过它可以获取相应的参数名信息. 除此之外, com.thoughtworks.paranamer:paranamer 这一工具包中的Paranamer 也可以同样进行相应信息的处理. 不过对于jdk8的methodParameters支持度还不是很高,使用者可以通过扩展它来达到自己的目的.
总结
以上就是为大家总结的Java获取代码中方法参数名信息的方法,希望对大家学习或使用Java带来一定的帮助,如果有疑问大家可以留言交流。