获取方法参数的名称

原文: https://docs.oracle.com/javase/tutorial/reflect/member/methodparameterreflection.html

您可以使用方法 java.lang.reflect.Executable.getParameters 获取任何方法或构造器的形式参数的名称。 (类 MethodConstructor 扩展类 Executable ,因此继承了Executable.getParameters方法。)但是,.class文件默认情况下不存储形式参数名称。这是因为许多生成和使用类文件的工具可能不会期望包含参数名称的.class文件的较大静态和动态占用空间。特别是,这些工具必须处理更大的.class文件,而 Java 虚拟机(JVM)将使用更多的内存。此外,某些参数名称(如secretpassword)可能会公开有关安全敏感方法的信息。

要将正式参数名称存储在特定的.class文件中,从而使 Reflection API 能够检索形式参数名称,请使用-parameters选项将源文件编译为javac编译器。

MethodParameterSpy 示例说明了如何检索给定类的所有构造器和方法的形式参数的名称。该示例还打印有关每个参数的其他信息。

以下命令打印类 ExampleMethods的构造器和方法的形式参数名称。 注意:记得使用-parameters编译器选项编译示例ExampleMethods

  1. java MethodParameterSpy ExampleMethods

此命令打印以下内容:

  1. Number of constructors: 1
  2. Constructor #1
  3. public ExampleMethods()
  4. Number of declared constructors: 1
  5. Declared constructor #1
  6. public ExampleMethods()
  7. Number of methods: 4
  8. Method #1
  9. public boolean ExampleMethods.simpleMethod(java.lang.String,int)
  10. Return type: boolean
  11. Generic return type: boolean
  12. Parameter class: class java.lang.String
  13. Parameter name: stringParam
  14. Modifiers: 0
  15. Is implicit?: false
  16. Is name present?: true
  17. Is synthetic?: false
  18. Parameter class: int
  19. Parameter name: intParam
  20. Modifiers: 0
  21. Is implicit?: false
  22. Is name present?: true
  23. Is synthetic?: false
  24. Method #2
  25. public int ExampleMethods.varArgsMethod(java.lang.String...)
  26. Return type: int
  27. Generic return type: int
  28. Parameter class: class [Ljava.lang.String;
  29. Parameter name: manyStrings
  30. Modifiers: 0
  31. Is implicit?: false
  32. Is name present?: true
  33. Is synthetic?: false
  34. Method #3
  35. public boolean ExampleMethods.methodWithList(java.util.List<java.lang.String>)
  36. Return type: boolean
  37. Generic return type: boolean
  38. Parameter class: interface java.util.List
  39. Parameter name: listParam
  40. Modifiers: 0
  41. Is implicit?: false
  42. Is name present?: true
  43. Is synthetic?: false
  44. Method #4
  45. public <T> void ExampleMethods.genericMethod(T[],java.util.Collection<T>)
  46. Return type: void
  47. Generic return type: void
  48. Parameter class: class [Ljava.lang.Object;
  49. Parameter name: a
  50. Modifiers: 0
  51. Is implicit?: false
  52. Is name present?: true
  53. Is synthetic?: false
  54. Parameter class: interface java.util.Collection
  55. Parameter name: c
  56. Modifiers: 0
  57. Is implicit?: false
  58. Is name present?: true
  59. Is synthetic?: false

MethodParameterSpy示例使用 Parameter 类中的以下方法:

  • getType :返回 Class 对象,该对象标识参数的声明类型。

  • getName :返回参数的名称。如果参数的名称存在,则此方法返回.class文件提供的名称。否则,该方法合成形式arg _N_的名称,其中_N_是该描述符中的参数的索引。声明参数的方法。

    例如,假设您编译了类ExampleMethods而未指定-parameters编译器选项。示例MethodParameterSpy将为方法ExampleMethods.simpleMethod打印以下内容:

    1. public boolean ExampleMethods.simpleMethod(java.lang.String,int)
    2. Return type: boolean
    3. Generic return type: boolean
    4. Parameter class: class java.lang.String
    5. Parameter name: arg0
    6. Modifiers: 0
    7. Is implicit?: false
    8. Is name present?: false
    9. Is synthetic?: false
    10. Parameter class: int
    11. Parameter name: arg1
    12. Modifiers: 0
    13. Is implicit?: false
    14. Is name present?: false
    15. Is synthetic?: false
  • getModifiers :返回一个整数,表示形式参数拥有的各种特征。如果适用于形式参数,则此值是以下值的总和:

    | 值(十进制) | 值(十六进制 | 描述 | | —- | —- | —- | | 16 | 0×0010 | 形式参数声明为final | | 4096 | 为 0x1000 | 形式参数是合成的。或者,您可以调用方法isSynthetic。 | | 32768 | 为 0x8000 | 该参数在源代码中隐式声明。或者,您可以调用方法isImplicit |

  • isImplicit :如果在源代码中隐式声明此参数,则返回true。有关详细信息,请参阅隐式和合成参数部分。

  • isNamePresent :如果参数根据.class文件具有名称,则返回true

  • isSynthetic :如果在源代码中既未隐式声明也未显式声明此参数,则返回true。有关详细信息,请参阅隐式和合成参数部分。

如果未明确编写某些构造,则会在源代码中隐式声明这些构造。例如, ExampleMethods示例不包含构造器。默认构造器是为它隐式声明的。 MethodParameterSpy示例打印有关ExampleMethods的隐式声明构造器的信息:

  1. Number of declared constructors: 1
  2. public ExampleMethods()

请考虑 MethodParameterExamples的以下摘录:

  1. public class MethodParameterExamples {
  2. public class InnerClass { }
  3. }

InnerClass是非静态嵌套类或内部类。内部类的构造器也是隐式声明的。但是,此构造器将包含一个参数。当 Java 编译器编译InnerClass时,它会创建一个代表类似于以下代码的.class文件:

  1. public class MethodParameterExamples {
  2. public class InnerClass {
  3. final MethodParameterExamples parent;
  4. InnerClass(final MethodParameterExamples this$0) {
  5. parent = this$0;
  6. }
  7. }
  8. }

InnerClass构造器包含一个参数,其类型是包含InnerClass的类,即MethodParameterExamples。因此,示例MethodParameterExamples打印以下内容:

  1. public MethodParameterExamples$InnerClass(MethodParameterExamples)
  2. Parameter class: class MethodParameterExamples
  3. Parameter name: this$0
  4. Modifiers: 32784
  5. Is implicit?: true
  6. Is name present?: true
  7. Is synthetic?: false

因为隐式声明了类InnerClass的构造器,所以它的参数也是隐式的。

  • Java 编译器为内部类的构造器创建形式参数,以使编译器能够将创建表达式中的引用(表示直接封闭的实例)传递给成员类的构造器。
  • 值 32784 表示InnerClass构造器的参数既是 final(16),也是隐式(32768)。
  • Java 编程语言允许带有美元符号的变量名称($);但是,按照惯例,美元符号不会用于变量名称。

如果 Java 编译器发出的构造与源代码中显式或隐式声明的构造不对应,则将其标记为 synthetic ,除非它们是类初始化方法。合成构造是由编译器生成的工件,这些工件在不同的实现之间变化。考虑以下 MethodParameterExamples的摘录:

  1. public class MethodParameterExamples {
  2. enum Colors {
  3. RED, WHITE;
  4. }
  5. }

当 Java 编译器遇到enum构造时,它会创建几个与.class文件结构兼容的方法,并提供enum构造的预期功能。例如,Java 编译器将为enum构造Colors创建一个.class文件,该文件表示类似于以下内容的代码:

  1. final class Colors extends java.lang.Enum {
  2. public final static Colors RED = new Colors("RED", 0);
  3. public final static Colors BLUE = new Colors("WHITE", 1);
  4. private final static values = new Colors[]{ RED, BLUE };
  5. private Colors(String name, int ordinal) {
  6. super(name, ordinal);
  7. }
  8. public static Colors[] values(){
  9. return values;
  10. }
  11. public static Colors valueOf(String name){
  12. return (Colors)java.lang.Enum.valueOf(Colors.class, name);
  13. }
  14. }

Java 编译器为此enum构造创建三个构造器和方法:Colors(String name, int ordinal)Colors[] values()Colors valueOf(String name)。方法valuesvalueOf是隐式声明的。因此,它们的形式参数名也被隐式声明。

enum构造器Colors(String name, int ordinal)是默认构造器,它是隐式声明的。但是,此构造器的形式参数(nameordinal)是而不是隐式声明的。由于这些形式参数既未明确声明也未隐式声明,因此它们是合成的。 (enum构造的默认构造器的形式参数不是隐式声明的,因为不同的编译器不需要在这个构造器的形式上达成一致;另一个 Java 编译器可能为它指定不同的形式参数。当编译器编译使用[COD5 的表达式]时]常量,它们仅依赖于enum构造的公共静态字段,这些字段是隐式声明的,而不是它们的构造器或这些常量的初始化方式。)

因此,示例MethodParameterExample打印有关enum构造Colors的以下内容:

  1. enum Colors:
  2. Number of constructors: 0
  3. Number of declared constructors: 1
  4. Declared constructor #1
  5. private MethodParameterExamples$Colors()
  6. Parameter class: class java.lang.String
  7. Parameter name: $enum$name
  8. Modifiers: 4096
  9. Is implicit?: false
  10. Is name present?: true
  11. Is synthetic?: true
  12. Parameter class: int
  13. Parameter name: $enum$ordinal
  14. Modifiers: 4096
  15. Is implicit?: false
  16. Is name present?: true
  17. Is synthetic?: true
  18. Number of methods: 2
  19. Method #1
  20. public static MethodParameterExamples$Colors[]
  21. MethodParameterExamples$Colors.values()
  22. Return type: class [LMethodParameterExamples$Colors;
  23. Generic return type: class [LMethodParameterExamples$Colors;
  24. Method #2
  25. public static MethodParameterExamples$Colors
  26. MethodParameterExamples$Colors.valueOf(java.lang.String)
  27. Return type: class MethodParameterExamples$Colors
  28. Generic return type: class MethodParameterExamples$Colors
  29. Parameter class: class java.lang.String
  30. Parameter name: name
  31. Modifiers: 32768
  32. Is implicit?: true
  33. Is name present?: true
  34. Is synthetic?: false

有关隐式声明的构造的更多信息,请参阅 Java 语言规范,包括在 Reflection API 中显示为隐式的参数。