默认情况下,我们是无法获取方法中参数名称的。通过反射机制,也只能得到参数的顺序以及一些没有意义的变量:arg0、arg1等等。
公司主营业务:成都网站设计、做网站、移动网站开发等业务。帮助企业客户真正实现互联网宣传,提高企业的竞争能力。成都创新互联是一支青春激扬、勤奋敬业、活力青春激扬、勤奋敬业、活力澎湃、和谐高效的团队。公司秉承以“开放、自由、严谨、自律”为核心的企业文化,感谢他们对我们的高要求,感谢他们从不同领域给我们带来的挑战,让我们激情的团队有机会用头脑与智慧不断的给客户带来惊喜。成都创新互联推出鞍山免费做网站回馈大家。
但我们又确实需要这部分信息。比如IDE的自动提示,文档化服务接口的详细信息等。
这是因为,这些变量的名字,根本就没有编译进class文件中,它不可能凭空产生。
在JDK 8之后,可以通过在编译时指定-parameters选项,将方法的参数名记入class文件,并在运行时通过反射机制获取相关信息。
如果你的项目是实用maven构建,那么就可以加入几行配置,追加参数。
maven-compiler-plugin 3.8.0 1.8 utf8 -parameters
如果是用的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("\t\t" + parameter.getName());
- //是否在源码中隐式声明的参数名
- System.out.println("\t\t\t implicit:" + parameter.isImplicit());
- //类文件中,是否存在参数名
- System.out.println("\t\t\t namePresent:" + parameter.isNamePresent());
- //是否为虚构参数
- System.out.println("\t\t\t synthetic:" + parameter.isSynthetic());
- System.out.println("\t\t\t 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("\t\t" + pn);
- }
- }
- }
- }
那Java版本低于1.8的时候,又是怎么获取的呢?我们可以参考Spring的LocalVariableTableParameterNameDiscoverer类。
- public String[] getParameterNames(Method method) {
- Method originalMethod = BridgeMethodResolver.findBridgedMethod(method);
- return doGetParameterNames(originalMethod);
- }
- @Nullable
- private String[] doGetParameterNames(Executable executable) {
- Class> declaringClass = executable.getDeclaringClass();
- Map
map = this.parameterNamesCache.computeIfAbsent(declaringClass, this::inspectClass); - return (map != NO_DEBUG_INFO_MAP ? map.get(executable) : null);
- }
最后就走到了inspectClass方法中。
- private Map
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
map = new ConcurrentHashMap<>(32); - classReader.accept(new ParameterNameDiscoveringVisitor(clazz, map), 0);
- return map;
- }
- ...
可以看到,这种情况下,Spring是通过直接读取class文件进行解析的。实际上是通过读取LocalVariableTable中的数据进行获取的。如果你编译的时候没有加入这些debug选项,同样也拿不到方法参数的具体名称。
总结一下
网页名称:Java如何获取方法参数具体名称?这是个好问题!
转载来源:http://www.shufengxianlan.com/qtweb/news7/220307.html
网站建设、网络推广公司-创新互联,是专注品牌与效果的网站制作,网络营销seo公司;服务项目有等
声明:本网站发布的内容(图片、视频和文字)以用户投稿、用户转载内容为主,如果涉及侵权请尽快告知,我们将会在第一时间删除。文章观点不代表本网站立场,如需处理请联系客服。电话:028-86922220;邮箱:631063699@qq.com。内容未经允许不得转载,或转载时需注明来源: 创新互联