java 获取运行时参数,Java8增强反射可以在运行时获取参数名

技术公众号:Java In Mind(Java_In_Mind),欢迎关注!

原文:Java8增强反射可以在运行时获取参数名

介绍

在JDK增强意见:JPE 118:Access to Parameter Names at Runtime中指出,在Java8中我们终于可以通过反射来获取方法的参数名,其主要的目的是:

提高代码的可读性(原先通常使用注解来实现)

可以提高IDE的功能

JDK8前获取参数名的方法

通过注解来实现

因为Java8之前不提供获取参数名称的功能,大部分实现都是通过提供注解元数据来标明参数名,这个也是目前许多框架使用的方法,如,SpringMVC的参数绑定,MyBatis的参数映射,类似:

//自定义@param注解

@Target(ElementType.PARAMETER)

@Retention(RetentionPolicy.RUNTIME)

@Documented

public @interface Param {

String value();

}

//声明参数名

public void foo(@Param("name") String name, @Param("count") int count){

System.out.println("name:=" + name + ",count=" + count);

}

//获取

Method foo = ParameterDemo.class.getMethod("foo", String.class, int.class);

Annotation[][] parameterAnnotations = foo.getParameterAnnotations();

for (Annotation[] parameterAnnotation : parameterAnnotations) {

for (Annotation annotation : parameterAnnotation) {

if(annotation instanceof Param){

System.out.println(((Param) annotation).value());

}

}

}

//获取结果

name

count

通过解析class文件

可以通过解析二进制文件来获取参数的名称,常见的工具有:ASM,javassist,如,Spring的LocalVariableTableParameterNameDiscoverer,就是利用ASM通过class文件中的本地方法变量表中获取到参数名称:

//使用Spring的LocalVariableTableParameterNameDiscoverer获取

public void foo(String name, int count){

System.out.println("name:=" + name + ",count=" + count);

}

Method foo = ParameterDemo.class.getMethod("foo", String.class, int.class);

String[] parameterNames = new LocalVariableTableParameterNameDiscoverer().getParameterNames(foo);

System.out.println(Arrays.toString(parameterNames));

//获取结果

[name, count]

使用Java8反射

JDK8在反射包中新增了Parameter类,用于表示方法的参数信息,通过Method来获取所有参数列表:

public void foo(String name, int count){

System.out.println("name:=" + name + ",count=" + count);

}

//通过反射获取

Method foo = ParameterDemo.class.getMethod("foo", String.class, int.class);

Parameter[] parameters = foo.getParameters();

for (Parameter parameter : parameters) {

System.out.println(parameter.getName());

}

//获取结果

name

count

【注意】

该功能需要在javac编译时开启-parameters参数,而为了兼容性该参数默认是不开启的,如果使用Maven构建的话可以如此配置:

org.apache.maven.plugins

maven-compiler-plugin

8

8

-parameters

【原理】

通过反编译可以知道,class文件保存了MethodParameters的信息,这就是保存方法名的地方:

//截取片段

public void foo(java.lang.String, int);

descriptor: (Ljava/lang/String;I)V

flags: ACC_PUBLIC

Code:

stack=3, locals=3, args_size=3

0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;

3: new #3 // class java/lang/StringBuilder

6: dup

7: invokespecial #4 // Method java/lang/StringBuilder."":()V

10: ldc #5 // String name:=

12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

15: aload_1

16: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

19: ldc #7 // String ,count=

21: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;

24: iload_2

25: invokevirtual #8 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;

28: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;

31: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V

34: return

LineNumberTable:

line 14: 0

line 15: 34

LocalVariableTable:

Start Length Slot Name Signature

0 35 0 this Lcom/sevenlin/demo/reflect/ParameterDemo;

0 35 1 name Ljava/lang/String;

0 35 2 count I

MethodParameters:

Name Flags

name

count

总结

Java运行时是使用位置解析参数的,但随着应用的发展,常常需要获取参数名的功能,如一些IDE的反编译功能,由于Java8之前不支持参数名的获取,通常都是通过别的方法来实现,通常就是通过注解,这会使代码比较混乱,而且冗余,降低代码阅读性,而通过解析class文件的方式来获取比较麻烦,而且也不提倡。

Java8对反射的增加也是为了解决以上的问题,而使用的时候注意要在编译时开启。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值