【问题标题】:Is there a way to obtain names of method parameters in Java? [duplicate]有没有办法在 Java 中获取方法参数的名称? [复制]
【发布时间】:2017-12-31 22:17:20
【问题描述】:

我正在编写非常小的 DRY 框架,它严重依赖元数据。我想知道是否有办法获取方法参数名称,即给定一些方法

public void a(int myIntParam, String theString) { ... }

获取字符串"myIntParam""theString"

我知道我可以注释参数,但那不是很好...

public void a(
    @Param("myIntParam") int myIntParam,
    @Param("theString") String theString
) { ... }

【问题讨论】:

  • 不是真的,但是 codehaus 有这个库可以用于很多目的:paranamer.codehaus.org
  • 天哪,我不知道这件事......我猜你每天都会学到一些东西!
  • 很有意思的东西。。但是我不想引入任何依赖,而且它的操作方式比较复杂。
  • 您在处理源文件或类吗?
  • 我在这里回答了同样的问题:stackoverflow.com/questions/2237803/…>

标签: java reflection


【解决方案1】:

这是一个肮脏的解决方案,需要进行一些调整。也许有人可以让它变得更好。

缺点:

  • 要求您知道已编译类文件的位置。
  • 必须使用 -g 标志进行编译。

代码:

import com.sun.org.apache.bcel.internal.classfile.ClassParser;
import com.sun.org.apache.bcel.internal.classfile.JavaClass;
import com.sun.org.apache.bcel.internal.classfile.LocalVariable;
import com.sun.org.apache.bcel.internal.classfile.Method;
import java.io.IOException;

public class Main {

  public static void main(String[] args) throws IOException {
      ClassParser parser = new ClassParser("Main.class");
      JavaClass clazz = parser.parse();

      for (Method m : clazz.getMethods()) {
          System.out.println("Method: " + m.getName());
          int size = m.getArgumentTypes().length;
          if (!m.isStatic()) {
            size++;
          }

          for (int i = 0; i < size; i++) {
              LocalVariable variable = m.getLocalVariableTable().getLocalVariable(i);
              System.out.println("  - Param: " + variable.getName());
          }
      }
  }

  public void a(int myIntParam, String theString) {
  }
}

输出:

$ javac -g Main.java
$ java Main
Method: &lt;init&gt;
- Param: this
Method: main
- Param: args
Method: a
- Param: this
- Param: myIntParam
- Param: theString

【讨论】:

    【解决方案2】:

    我可能错了……但我不认为参数名称出现在类文件中,所以我猜想没有办法通过反射来获取它们。

    【讨论】:

      【解决方案3】:

      我们为包含参数名称的 String[] 的方法创建了一个自定义注解。这种方法感觉比必须注释每个单独的参数更容易管理。我们计划添加构建时检查带注释的参数名称的数量是否与参数的数量匹配,因为这是我们需要的。

      【讨论】:

      • 好主意!我肯定会将所有这些@Param 转换为单个@Params。
      • 其实我更喜欢单独注释它们,因为这使得注释是可选的。我使用这些注释来创建一个网页以使用反射调用方法。如果我忘记注释参数,那么代码就会退回并将其可视化为最终用户的“paramX”。另一方面,如果您将所有名称都放在一个注释中,那么就没有像样的回退。
      【解决方案4】:

      当使用调试信息(通过 -g 选项)编译 java 代码时,参数的名称存在于类文件中。然后类文件包含一个 LocalVariableTable 属性(请参阅http://java.sun.com/docs/books/jvms/second_edition/html/ClassFile.doc.html#5956)。这包含局部变量的名称,参数只是局部变量。参数对应于从索引 1 开始的变量槽(或静态方法的索引 0)。

      【讨论】:

        【解决方案5】:

        如果您使用的是 Spring,那么您很幸运。只需将其添加到您的 applicationContext.xml:

        <bean class="org.springframework.core.LocalVariableTableParameterNameDiscoverer"/>
        

        然后你可以在需要的地方注入这个bean:

        @Autowired
        private ParameterNameDiscoverer parameterNameDiscoverer;
        
        Method m = ...
        String[] names = parameterNameDiscoverer.getParameterNames(m);
        

        顾名思义,此实现依赖于使用调试信息编译的类。

        【讨论】:

          【解决方案6】:

          @bobwienholt 是正确的 - 参数名称未编译到 Java 类中,因此在运行时不可用。

          【讨论】:

            【解决方案7】:

            参数名称可通过apt(现在是 javac 的一部分)获得。

            【讨论】:

            • @Tom:您还需要显式注释类以易于预处理它们吗?还是现在有更通用的预编译器?
            • 我相信注释处理器可以要求接收所有类,无论它们是否有注释。它不是真正的预处理器,因为原始类被单独保留,尽管可以创建其他类和工件。
            猜你喜欢
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 1970-01-01
            • 2017-01-27
            • 2023-01-17
            • 2013-01-08
            相关资源
            最近更新 更多