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

相关文章

PHP轻松处理千万行数据的方法详解

《PHP轻松处理千万行数据的方法详解》说到处理大数据集,PHP通常不是第一个想到的语言,但如果你曾经需要处理数百万行数据而不让服务器崩溃或内存耗尽,你就会知道PHP用对了工具有多强大,下面小编就... 目录问题的本质php 中的数据流处理:为什么必不可少生成器:内存高效的迭代方式流量控制:避免系统过载一次性

python获取指定名字的程序的文件路径的两种方法

《python获取指定名字的程序的文件路径的两种方法》本文主要介绍了python获取指定名字的程序的文件路径的两种方法,文中通过示例代码介绍的非常详细,对大家的学习或者工作具有一定的参考学习价值,需要... 最近在做项目,需要用到给定一个程序名字就可以自动获取到这个程序在Windows系统下的绝对路径,以下

JavaScript中的高级调试方法全攻略指南

《JavaScript中的高级调试方法全攻略指南》什么是高级JavaScript调试技巧,它比console.log有何优势,如何使用断点调试定位问题,通过本文,我们将深入解答这些问题,带您从理论到实... 目录观点与案例结合观点1观点2观点3观点4观点5高级调试技巧详解实战案例断点调试:定位变量错误性能分

Python中 try / except / else / finally 异常处理方法详解

《Python中try/except/else/finally异常处理方法详解》:本文主要介绍Python中try/except/else/finally异常处理方法的相关资料,涵... 目录1. 基本结构2. 各部分的作用tryexceptelsefinally3. 执行流程总结4. 常见用法(1)多个e

JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法

《JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法》:本文主要介绍JavaScript中比较两个数组是否有相同元素(交集)的三种常用方法,每种方法结合实例代码给大家介绍的非常... 目录引言:为什么"相等"判断如此重要?方法1:使用some()+includes()(适合小数组)方法2

SpringBoot 获取请求参数的常用注解及用法

《SpringBoot获取请求参数的常用注解及用法》SpringBoot通过@RequestParam、@PathVariable等注解支持从HTTP请求中获取参数,涵盖查询、路径、请求体、头、C... 目录SpringBoot 提供了多种注解来方便地从 HTTP 请求中获取参数以下是主要的注解及其用法:1

HTTP 与 SpringBoot 参数提交与接收协议方式

《HTTP与SpringBoot参数提交与接收协议方式》HTTP参数提交方式包括URL查询、表单、JSON/XML、路径变量、头部、Cookie、GraphQL、WebSocket和SSE,依据... 目录HTTP 协议支持多种参数提交方式,主要取决于请求方法(Method)和内容类型(Content-Ty

504 Gateway Timeout网关超时的根源及完美解决方法

《504GatewayTimeout网关超时的根源及完美解决方法》在日常开发和运维过程中,504GatewayTimeout错误是常见的网络问题之一,尤其是在使用反向代理(如Nginx)或... 目录引言为什么会出现 504 错误?1. 探索 504 Gateway Timeout 错误的根源 1.1 后端

linux系统上安装JDK8全过程

《linux系统上安装JDK8全过程》文章介绍安装JDK的必要性及Linux下JDK8的安装步骤,包括卸载旧版本、下载解压、配置环境变量等,强调开发需JDK,运行可选JRE,现JDK已集成JRE... 目录为什么要安装jdk?1.查看linux系统是否有自带的jdk:2.下载jdk压缩包2.解压3.配置环境

MySQL 表空却 ibd 文件过大的问题及解决方法

《MySQL表空却ibd文件过大的问题及解决方法》本文给大家介绍MySQL表空却ibd文件过大的问题及解决方法,本文给大家介绍的非常详细,对大家的学习或工作具有一定的参考借鉴价值,需要的朋友参考... 目录一、问题背景:表空却 “吃满” 磁盘的怪事二、问题复现:一步步编程还原异常场景1. 准备测试源表与数据