原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处。

默认情况下,我们是无法获取方法中参数名称的。通过反射机制,也只能得到参数的顺序以及一些没有意义的变量:arg0arg1等等。

但我们又确实需要这部分信息。比如IDE的自动提示,文档化服务接口的详细信息等。

这是因为,这些变量的名字,根本就没有编译进class文件中,它不可能凭空产生。

在JDK 8之后,可以通过在编译时指定-parameters选项,将方法的参数名记入class文件,并在运行时通过反射机制获取相关信息。

如果你的项目是实用maven构建,那么就可以加入几行配置,追加参数。

<plugin>  <artifactId>maven-compiler-plugin</artifactId>  <version>3.8.0</version>  <configuration>  <source>1.8</source>  <target>1.8</target>  <encoding>utf8</encoding>  <compilerArgs>  <arg>-parameters</arg>  </compilerArgs>  </configuration>  </plugin>

如果是用的IDEA等编辑器,也可以通过设置界面进行配置。不过不推荐这样,因为你的这些配置不好进行共享。

在普通Java项目里,就可以通过下面的方式来获取反射数据。Method.getParameters这个方法是新加的。

public class Test {  public static void main(String[] args) throws Exception{  Class clazz = Class.forName("com.test.MethodParameterTest");  Method[] methods = clazz.getMethods();  Constructor[] constructors = clazz.getConstructors();  for (Constructor constructor : constructors) {  System.out.println("+++" + constructor.getName());  Parameter[] parameters = constructor.getParameters();  for (Parameter parameter : parameters) {  printParameter(parameter);  }  }  System.out.println("------------------");  for (Method method : methods) {  System.out.println(method.getName());  Parameter[] parameters = method.getParameters();  for (Parameter parameter : parameters) {  printParameter(parameter);  }  }  }  private static void printParameter(Parameter parameter) {  //参数名  System.out.println("tt" + parameter.getName());  //是否在源码中隐式声明的参数名  System.out.println("ttt implicit:" + parameter.isImplicit());  //类文件中,是否存在参数名  System.out.println("ttt namePresent:" + parameter.isNamePresent());  //是否为虚构参数  System.out.println("ttt synthetic:" + parameter.isSynthetic());  System.out.println("ttt VarArgs:" + parameter.isVarArgs());  }  }

下面介绍几个方法的意义:

isImplicit()

参数是否为隐式声明在源文件中,比如内部类,默认构造函数(无参)其实在编译成class时将会把包含它的主类引用作为首个参数,此参数即为隐式声明。

如果为true,即表示有JDK编译器隐式生成在class文件中的方法参数,而source文件中并不可见。常规的普通方法,此值为false。

isNamePresent()

此参数在class文件中是否有此参数名;受制于在编译时是否指定了“-parameter”,对于指定此参数的编译文件,通常为true;对于JDK 内部类、默认编译的类,通常为false;此时你会发现,它们的参数名通常为表意名称:arg0、arg1等等,此时为false。

isSynthetic()

是否为“虚构”参数,如果为true,表示既不是“显式”声明、也不是隐式声明在源文件中的参数,比如enum类的“values()”、“valueOf(String)”这是编译器“虚构”的系统方法。

在Spring环境中,由于有工具类的支持,会更加方便一些。

public class SpringTest {  private static final ParameterNameDiscoverer parameterNameDiscoverer = new DefaultParameterNameDiscoverer();  public static void main(String[] args) throws Exception{  Class clazz = Class.forName("com.test.MethodParameterTest");  Method[] methods = clazz.getMethods();  for (Method method : methods) {  System.out.println(method.getName());  //JDK 1.8 + is better.  String[] parameterNames = parameterNameDiscoverer.getParameterNames(method);  if (parameterNames == null) {  continue;  }  for (String pn : parameterNames) {  System.out.println("tt" + pn);  }  }  }  }

那Java版本低于1.8的时候,又是怎么获取的呢?我们可以参考Spring的LocalVariableTableParameterNameDiscoverer类。

public String[] getParameterNames(Method method) {Method originalMethod = BridgeMethodResolver.findBridgedMethod(method);return doGetParameterNames(originalMethod);}@Nullableprivate String[] doGetParameterNames(Executable executable) {Class<?> declaringClass = executable.getDeclaringClass();Map<Executable, String[]> map = this.parameterNamesCache.computeIfAbsent(declaringClass, this::inspectClass);return (map != NO_DEBUG_INFO_MAP ? map.get(executable) : null);}

最后就走到了inspectClass方法中。

private Map<Executable, String[]> inspectClass(Class<?> clazz) {InputStream is = clazz.getResourceAsStream(ClassUtils.getClassFileName(clazz));if (is == null) {// We couldn't load the class file, which is not fatal as it// simply means this method of discovering parameter names won't work.if (logger.isDebugEnabled()) {logger.debug("Cannot find '.class' file for class [" + clazz +"] - unable to determine constructor/method parameter names");}return NO_DEBUG_INFO_MAP;}try {ClassReader classReader = new ClassReader(is);Map<Executable, String[]> map = new ConcurrentHashMap<>(32);classReader.accept(new ParameterNameDiscoveringVisitor(clazz, map), 0);return map;}...

可以看到,这种情况下,Spring是通过直接读取class文件进行解析的。实际上是通过读取LocalVariableTable中的数据进行获取的。如果你编译的时候没有加入这些debug选项,同样也拿不到方法参数的具体名称。

总结一下。Java8以前,读取Class中的LocalVariableTable属性表,需要编译时加入参数-g或者-g:vars 获取方法局部变量调试信息;Java8及其以后,通过java.lang.reflect.Parameter#getName即可获取,但需要编译时加入参数-parameters参数。

作者简介:小姐姐味道 (xjjdog),一个不允许程序员走弯路的公众号。聚焦基础架构和Linux。十年架构,日百亿流量,与你探讨高并发世界,给你不一样的味道。我的个人微信xjjdog0,欢迎添加好友,​进一步交流。​

java xfire指定参数名_Java如何获取方法参数具体名称?这是个好问题!相关推荐

  1. class? clazz参数_Java如何获取方法参数具体名称?这是个好问题!

    原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处. 默认情况下,我们是无法获取方法中参数名称的.通过反射机制,也只能得到参数的顺序以及一些没有意义的变量:arg0.arg1等 ...

  2. class? clazz参数_Java如何获取方法参数具体名称?这是个好问题

    原创:小姐姐味道(微信公众号ID:xjjdog),欢迎分享,转载请保留出处. 默认情况下,我们是无法获取方法中参数名称的.通过反射机制,也只能得到参数的顺序以及一些没有意义的变量:arg0.arg1等 ...

  3. java 文件去除扩展名_Java操作——获取文件扩展名,去掉文件扩展名

    昨天收邮件,得知要参加一个产品部的会议,猜想,也许是因为我做的这个产品demo问题.于是昨天忙活到凌晨3点半,结果早上一来才知道又被调戏了.发邮件的MM把邮件误发给我了.悲催啊有木有,困啊有木有!自己 ...

  4. 如何获取java对象的字段名_Java如何获取类对象的字段?

    下面的示例使用反射获取类对象的字段.我们将获取字段名称及其对应的类型.下面显示了三种可用于获取对象字段的方式:Class.getDeclaredFields() Class.getFields() C ...

  5. java 反射 参数名_JAVA 8 反射获取参数名

    前言 在JDK8之前javac编译是不会把构造器和方法的参数名编译进class中,如果需要获取参数名,可以在方法上加上注解,反射获取注解的值从而获取参数名,比如Jackson的@JsonCreator ...

  6. java反射 获取方法参数名_java 反射借助 asm 获取参数名称最优雅简单的方式

    背景说明 最近写反射相关的代码,想获取对应的参数名称,却发现没有特别好的方式. jdk7 及其以前,是无法通过反射获取参数名称的. jdk8 可以获取,但是要求指定 -parameter 启动参数,限 ...

  7. java:axis2环境下获取方法参数名的另一种方法

    java本身提供的方法不能获取方法的参数名的,只能获取每个参数的类型 比如: public String concatString(String param1,String param2){retur ...

  8. 【Java从零到架构师第③季】【26】SpringMVC-反射获取方法参数名_SpringMVC是如何获取方法的参数名的

    持续学习&持续更新中- 守破离 [Java从零到架构师第③季][26]SpringMVC-反射获取方法参数名_SpringMVC是如何获取方法的参数名的 利用反射获取方法的参数名 直接编译 修 ...

  9. java xfire指定参数名_xfire中自定义参数名

    近期在做多个应用交互系统,其中数据交互采用了webservice的方式,说到webservice项目中不得不用到xfire这个框架,有了它我们几乎不用写代码,就可以很快速的创建自己的webservic ...

最新文章

  1. RS232接口是如何工作的?
  2. 易百教程人工智能python修正-人工智能无监督学习(聚类)
  3. Java面试题 synchronized底层实现原理?它与lock相比有什么优缺点?
  4. Java 入门基础——面向对象的特征
  5. cleanmymac X 4.7.3更新(支持M1芯片)
  6. wpf webbrowser获取选中文本_网页文本高亮插件 web-marker
  7. Dagger2的使用示例
  8. 北京中波(AM-MW)无线广播发射频率/频道表 (转载)
  9. Android 设置全屏样式主题的总结
  10. Android实现通过浏览器点击链接打开本地应用(APP)
  11. vs code修改代码后再次运行,报错:file“<stdin>“,line 1
  12. android 数据图标的刷新通知流程
  13. 处理器与大力神杯,夺冠或许并不需要11人
  14. Java性能调优杀手锏JMH
  15. C专家编程(Expert C Programming)1
  16. 4.4 基金排行数据(Python)
  17. Received disconnect from xxx.xxx.xxx port 22:2: Too many authentication failures for git
  18. java语言基础知识(完整版)
  19. opencart修改后台文件夹名
  20. 图书条形码跟ISBN号互相转换的类(续)

热门文章

  1. Basic Oracle Net Services Client-Side Configuration
  2. .Net Attribute特性
  3. [转]把复杂事物简明化
  4. YAML_15 include and roles
  5. webpack 的使用1
  6. 一个年轻的码农的一个C#项目
  7. R 语言在数据处理上的禀赋之——独特的数据类型
  8. 深搜--1-n的全排列
  9. 一开机未通过输入密码登录,就出现用户名或密码错误??
  10. 转(每天淘汰你自己)