JDK8新特性-反射获取方法的参数名称

2024-05-26 19:18

本文主要是介绍JDK8新特性-反射获取方法的参数名称,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!

在JDK8之前,java编译器会忽略我们编写代码时候设定的参数名,比如在mybatis框架中,我们可以使用@Param注解来让mybatis知道参数名。

public interface DemoMapper {    List<Card> getCardList(@Param("cardIds") List<Integer> cardIds);    Card getCard(@Param("cardId")int cardId);
}

很长一段时间里,Java程序员一直在发明不同的方式使得方法参数的名字能保留在Java字节码中,并且能够在运行时获取它们(比如Paranamer类库-Java 8开始增加了类Parameter,在class文件中保留参数名,给反射带来了极大的便利)。最终,在Java 8中把这个强烈要求的功能添加到语言层面(通过反射API与Parameter.getName()方法)与字节码文件(通过新版的javac的–parameters选项)中。

public class ParameterNames {public static void main(String[] args) throws Exception {Method method = ParameterNames.class.getMethod("main", String[].class);for (final Parameter parameter : method.getParameters()) {// 参数名称是否存在System.out.println("isNamePresent: " + parameter.isNamePresent());System.out.println("Parameter: " + parameter.getName());}}
}

如果不使用–parameters参数来编译这个类,然后运行这个类,会得到下面的输出:

isNamePresent: false    
Parameter: arg0

如果使用–parameters参数来编译这个类,参数的真实名字将会显示出来:

isNamePresent: true
Parameter: args

项目中使用–parameters前后记得先 重新编译下项目代码(Build -> Rebuild Project)

 

还原Spring MVC获取参数名的场景

public static void main(String[] args) throws NoSuchMethodException {Method method = Main.class.getMethod("test1", String.class, Integer.class);MethodParameter nameParameter = new MethodParameter(method, 0);MethodParameter ageParameter = new MethodParameter(method, 1);// 打印输出:// 使用Parameter输出Parameter nameOriginParameter = nameParameter.getParameter();Parameter ageOriginParameter = ageParameter.getParameter();System.out.println("===================源生Parameter结果=====================");System.out.println(nameOriginParameter.getType() + "----" + nameOriginParameter.getName());System.out.println(ageOriginParameter.getType() + "----" + ageOriginParameter.getName());System.out.println("===================MethodParameter结果=====================");System.out.println(nameParameter.getParameterType() + "----" + nameParameter.getParameterName());System.out.println(ageParameter.getParameterType() + "----" + ageParameter.getParameterName());System.out.println("==============设置上ParameterNameDiscoverer后MethodParameter结果===============");ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();nameParameter.initParameterNameDiscovery(parameterNameDiscoverer);ageParameter.initParameterNameDiscovery(parameterNameDiscoverer);System.out.println(nameParameter.getParameterType() + "----" + nameParameter.getParameterName());System.out.println(ageParameter.getParameterType() + "----" + ageParameter.getParameterName());
}

输出结果:

===================源生Parameter结果=====================
class java.lang.String----arg0
class java.lang.Integer----arg1
===================MethodParameter结果=====================
class java.lang.String----null
class java.lang.Integer----null
==============设置上ParameterNameDiscovererMethodParameter结果===============
class java.lang.String----name
class java.lang.Integer----age

从结果能看出来:Spring MVC借助ParameterNameDiscoverer完成了方法参数名的获取,进而完成数据封装。关于ParameterNameDiscoverer它的讲解,可先行参阅:【小家Spring】Spring标准处理组件大合集(ParameterNameDiscoverer、AutowireCandidateResolver、ResolvableType。。。)

 

Spring中获取方法参数名的工具LocalVariableTableParameterNameDiscoverer

public class Main {private static final ParameterNameDiscoverer parameterNameDiscoverer = new LocalVariableTableParameterNameDiscoverer();public void testArguments(String test, Integer myInteger, boolean booleanTest) {}public void test() {}public static void main(String[] args) {Method[] methods = Main.class.getDeclaredMethods();for (Method method : methods) {String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);System.out.println("方法:" + method.getName() + " 参数为:" + Arrays.asList(parameterNames));for (Parameter parameter : method.getParameters()) {System.out.println(parameter.getName());}}}}

 

使用-parameters获取方法参数名

最为简单直接的方式,Java8源生支持:直接从java.lang.reflect.Parameter就能获取到,形如这样:

public class MainTest2 {public static void main(String[] args) throws NoSuchMethodException {Method method = MainTest2.class.getMethod("testArgName", String.class, Integer.class);System.out.println("paramCount:" + method.getParameterCount());for (Parameter parameter : method.getParameters()) {System.out.println(parameter.getType().getName() + "-->" + parameter.getName());}}public String testArgName(String name, Integer age) {return null;}
}

输出:

paramCount:2
java.lang.String-->name
java.lang.Integer-->age

当然,它有两个最大的弊端:

  1. 必须Java8或以上(由于java8已经普及率非常高了,所以这个还好)
  2. 编译时候必须有编译选项:-parameters打开,默认是关闭的。(由于依赖编译参数,所以对迁移是不太友好的,这点比较致命)

指定-parameters编译参数的方式:

  1. 手动命令方式编译:javac -parameters XXX.java

  2. IDE(以Idea为例)编译:Settings -> Build,Execution,Deployment -> Compiler -> Java Compiler

    • Additional command line parameters框中设置为-parameters
    • Override compiler parameters per-module中新增一个module并设置 Compilation options值为-parameters
  3. Maven编译:通过编译插件指定,保证项目迁移的正确性(推荐

<!-- 编译环境在1.8编译 且附加编译参数:-parameters-->
<plugin><groupId>org.apache.maven.plugins</groupId><artifactId>maven-compiler-plugin</artifactId><version>3.8.0</version><configuration><compilerArgs><arg>-parameters</arg></compilerArgs><source>${java.version}</source><target>${java.version}</target><compilerVersion>${java.version}</compilerVersion><encoding>${project.build.sourceEncoding}</encoding></configuration>
</plugin>

 

References

  • Apache Maven Project
  • 通过反射获取方法参数名时遇到的小坑
  • Java如何获取方法的参数名称?
  • JDK8新特性:编译器保留方法参数名字
  • 为何Spring MVC可获取到方法参数名,而MyBatis却不行?【享学Spring MVC】

这篇关于JDK8新特性-反射获取方法的参数名称的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!



http://www.chinasem.cn/article/1005356

相关文章

postgresql使用UUID函数的方法

《postgresql使用UUID函数的方法》本文给大家介绍postgresql使用UUID函数的方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考下吧... 目录PostgreSQL有两种生成uuid的方法。可以先通过sql查看是否已安装扩展函数,和可以安装的扩展函数

Java中Arrays类和Collections类常用方法示例详解

《Java中Arrays类和Collections类常用方法示例详解》本文总结了Java中Arrays和Collections类的常用方法,涵盖数组填充、排序、搜索、复制、列表转换等操作,帮助开发者高... 目录Arrays.fill()相关用法Arrays.toString()Arrays.sort()A

Nginx安全防护的多种方法

《Nginx安全防护的多种方法》在生产环境中,需要隐藏Nginx的版本号,以避免泄漏Nginx的版本,使攻击者不能针对特定版本进行攻击,下面就来介绍一下Nginx安全防护的方法,感兴趣的可以了解一下... 目录核心安全配置1.编译安装 Nginx2.隐藏版本号3.限制危险请求方法4.请求限制(CC攻击防御)

python生成随机唯一id的几种实现方法

《python生成随机唯一id的几种实现方法》在Python中生成随机唯一ID有多种方法,根据不同的需求场景可以选择最适合的方案,文中通过示例代码介绍的非常详细,需要的朋友们下面随着小编来一起学习学习... 目录方法 1:使用 UUID 模块(推荐)方法 2:使用 Secrets 模块(安全敏感场景)方法

一文详解如何使用Java获取PDF页面信息

《一文详解如何使用Java获取PDF页面信息》了解PDF页面属性是我们在处理文档、内容提取、打印设置或页面重组等任务时不可或缺的一环,下面我们就来看看如何使用Java语言获取这些信息吧... 目录引言一、安装和引入PDF处理库引入依赖二、获取 PDF 页数三、获取页面尺寸(宽高)四、获取页面旋转角度五、判断

MyBatis-Plus通用中等、大量数据分批查询和处理方法

《MyBatis-Plus通用中等、大量数据分批查询和处理方法》文章介绍MyBatis-Plus分页查询处理,通过函数式接口与Lambda表达式实现通用逻辑,方法抽象但功能强大,建议扩展分批处理及流式... 目录函数式接口获取分页数据接口数据处理接口通用逻辑工具类使用方法简单查询自定义查询方法总结函数式接口

MySQL深分页进行性能优化的常见方法

《MySQL深分页进行性能优化的常见方法》在Web应用中,分页查询是数据库操作中的常见需求,然而,在面对大型数据集时,深分页(deeppagination)却成为了性能优化的一个挑战,在本文中,我们将... 目录引言:深分页,真的只是“翻页慢”那么简单吗?一、背景介绍二、深分页的性能问题三、业务场景分析四、

JAVA中安装多个JDK的方法

《JAVA中安装多个JDK的方法》文章介绍了在Windows系统上安装多个JDK版本的方法,包括下载、安装路径修改、环境变量配置(JAVA_HOME和Path),并说明如何通过调整JAVA_HOME在... 首先去oracle官网下载好两个版本不同的jdk(需要登录Oracle账号,没有可以免费注册)下载完

Spring Boot spring-boot-maven-plugin 参数配置详解(最新推荐)

《SpringBootspring-boot-maven-plugin参数配置详解(最新推荐)》文章介绍了SpringBootMaven插件的5个核心目标(repackage、run、start... 目录一 spring-boot-maven-plugin 插件的5个Goals二 应用场景1 重新打包应用

Java中读取YAML文件配置信息常见问题及解决方法

《Java中读取YAML文件配置信息常见问题及解决方法》:本文主要介绍Java中读取YAML文件配置信息常见问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要... 目录1 使用Spring Boot的@ConfigurationProperties2. 使用@Valu