# 获取方法参数的名称

> 原文： [https://docs.oracle.com/javase/tutorial/reflect/member/methodparameterreflection.html](https://docs.oracle.com/javase/tutorial/reflect/member/methodparameterreflection.html)

您可以使用方法 [`java.lang.reflect.Executable.getParameters`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Executable.html#getParameters--) 获取任何方法或构造函数的形式参数的名称。 （类 [`Method`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Method.html) 和 [`Constructor`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Executable.html) 扩展类 [`Executable`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Executable.html) ，因此继承了`Executable.getParameters`方法。）但是，`.class`文件默认情况下不存储形式参数名称。这是因为许多生成和使用类文件的工具可能不会期望包含参数名称的`.class`文件的较大静态和动态占用空间。特别是，这些工具必须处理更大的`.class`文件，而 Java 虚拟机（JVM）将使用更多的内存。此外，某些参数名称（如`secret`或`password`）可能会公开有关安全敏感方法的信息。

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

[``MethodParameterSpy`` ](example/MethodParameterSpy.java)示例说明了如何检索给定类的所有构造函数和方法的形式参数的名称。该示例还打印有关每个参数的其他信息。

以下命令打印类 [``ExampleMethods``](example/ExampleMethods.java)的构造函数和方法的形式参数名称。 **注意**：记得使用`-parameters`编译器选项编译示例`ExampleMethods`：

```
java MethodParameterSpy ExampleMethods
```

此命令打印以下内容：

```
Number of constructors: 1

Constructor #1
public ExampleMethods()

Number of declared constructors: 1

Declared constructor #1
public ExampleMethods()

Number of methods: 4

Method #1
public boolean ExampleMethods.simpleMethod(java.lang.String,int)
             Return type: boolean
     Generic return type: boolean
         Parameter class: class java.lang.String
          Parameter name: stringParam
               Modifiers: 0
            Is implicit?: false
        Is name present?: true
           Is synthetic?: false
         Parameter class: int
          Parameter name: intParam
               Modifiers: 0
            Is implicit?: false
        Is name present?: true
           Is synthetic?: false

Method #2
public int ExampleMethods.varArgsMethod(java.lang.String...)
             Return type: int
     Generic return type: int
         Parameter class: class [Ljava.lang.String;
          Parameter name: manyStrings
               Modifiers: 0
            Is implicit?: false
        Is name present?: true
           Is synthetic?: false

Method #3
public boolean ExampleMethods.methodWithList(java.util.List<java.lang.String>)
             Return type: boolean
     Generic return type: boolean
         Parameter class: interface java.util.List
          Parameter name: listParam
               Modifiers: 0
            Is implicit?: false
        Is name present?: true
           Is synthetic?: false

Method #4
public <T> void ExampleMethods.genericMethod(T[],java.util.Collection<T>)
             Return type: void
     Generic return type: void
         Parameter class: class [Ljava.lang.Object;
          Parameter name: a
               Modifiers: 0
            Is implicit?: false
        Is name present?: true
           Is synthetic?: false
         Parameter class: interface java.util.Collection
          Parameter name: c
               Modifiers: 0
            Is implicit?: false
        Is name present?: true
           Is synthetic?: false
```

`MethodParameterSpy`示例使用 [`Parameter`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Parameter.html) 类中的以下方法：

*   [`getType`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Parameter.html#getType--) ：返回 [`Class`](https://docs.oracle.com/javase/8/docs/api/java/lang/Class.html) 对象，该对象标识参数的声明类型。

*   [`getName`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Parameter.html#getName--) ：返回参数的名称。如果参数的名称存在，则此方法返回`.class`文件提供的名称。否则，该方法合成形式 `arg _N_`的名称，其中 `_N_`是该描述符中的参数的索引。声明参数的方法。

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

    ```
    public boolean ExampleMethods.simpleMethod(java.lang.String,int)
                 Return type: boolean
         Generic return type: boolean
             Parameter class: class java.lang.String
              Parameter name: arg0
                   Modifiers: 0
                Is implicit?: false
            Is name present?: false
               Is synthetic?: false
             Parameter class: int
              Parameter name: arg1
                   Modifiers: 0
                Is implicit?: false
            Is name present?: false
               Is synthetic?: false
    ```

*   [`getModifiers`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Parameter.html#getModifiers--) ：返回一个整数，表示形式参数拥有的各种特征。如果适用于形式参数，则此值是以下值的总和：

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

*   [`isImplicit`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Parameter.html#isImplicit--) ：如果在源代码中隐式声明此参数，则返回`true`。有关详细信息，请参阅[隐式和合成参数](#implcit_and_synthetic)部分。

*   [`isNamePresent`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Parameter.html#isNamePresent--) ：如果参数根据`.class`文件具有名称，则返回`true`。

*   [`isSynthetic`](https://docs.oracle.com/javase/8/docs/api/java/lang/reflect/Parameter.html#isSynthetic--) ：如果在源代码中既未隐式声明也未显式声明此参数，则返回`true`。有关详细信息，请参阅[隐式和合成参数](#implcit_and_synthetic)部分。

如果未明确编写某些构造，则会在源代码中隐式声明这些构造。例如， [``ExampleMethods``](example/ExampleMethods.java)示例不包含构造函数。默认构造函数是为它隐式声明的。 `MethodParameterSpy`示例打印有关`ExampleMethods`的隐式声明构造函数的信息：

```
Number of declared constructors: 1
public ExampleMethods()
```

请考虑 [``MethodParameterExamples``](example/MethodParameterExamples.java)的以下摘录：

```
public class MethodParameterExamples {
    public class InnerClass { }
}
```

类`InnerClass`是非静态[嵌套类](../../java/javaOO/nested.html)或内部类。内部类的构造函数也是隐式声明的。但是，此构造函数将包含一个参数。当 Java 编译器编译`InnerClass`时，它会创建一个代表类似于以下代码的`.class`文件：

```
public class MethodParameterExamples {
    public class InnerClass {
        final MethodParameterExamples parent;
        InnerClass(final MethodParameterExamples this$0) {
            parent = this$0; 
        }
    }
}
```

`InnerClass`构造函数包含一个参数，其类型是包含`InnerClass`的类，即`MethodParameterExamples`。因此，示例`MethodParameterExamples`打印以下内容：

```
public MethodParameterExamples$InnerClass(MethodParameterExamples)
         Parameter class: class MethodParameterExamples
          Parameter name: this$0
               Modifiers: 32784
            Is implicit?: true
        Is name present?: true
           Is synthetic?: false
```

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

**注**：

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

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

```
public class MethodParameterExamples {
    enum Colors {
        RED, WHITE;
    }
}
```

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

```
final class Colors extends java.lang.Enum<Colors> {
    public final static Colors RED = new Colors("RED", 0);
    public final static Colors BLUE = new Colors("WHITE", 1);

    private final static values = new Colors[]{ RED, BLUE };

    private Colors(String name, int ordinal) {
        super(name, ordinal);
    }

    public static Colors[] values(){
        return values;
    }

    public static Colors valueOf(String name){
        return (Colors)java.lang.Enum.valueOf(Colors.class, name);
    }
}
```

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

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

因此，示例`MethodParameterExample`打印有关`enum`构造`Colors`的以下内容：

```
enum Colors:

Number of constructors: 0

Number of declared constructors: 1

Declared constructor #1
private MethodParameterExamples$Colors()
         Parameter class: class java.lang.String
          Parameter name: $enum$name
               Modifiers: 4096
            Is implicit?: false
        Is name present?: true
           Is synthetic?: true
         Parameter class: int
          Parameter name: $enum$ordinal
               Modifiers: 4096
            Is implicit?: false
        Is name present?: true
           Is synthetic?: true

Number of methods: 2

Method #1
public static MethodParameterExamples$Colors[]
    MethodParameterExamples$Colors.values()
             Return type: class [LMethodParameterExamples$Colors;
     Generic return type: class [LMethodParameterExamples$Colors;

Method #2
public static MethodParameterExamples$Colors
    MethodParameterExamples$Colors.valueOf(java.lang.String)
             Return type: class MethodParameterExamples$Colors
     Generic return type: class MethodParameterExamples$Colors
         Parameter class: class java.lang.String
          Parameter name: name
               Modifiers: 32768
            Is implicit?: true
        Is name present?: true
           Is synthetic?: false
```

有关隐式声明的构造的更多信息，请参阅 [Java 语言规范](https://docs.oracle.com/javase/specs/)，包括在 Reflection API 中显示为隐式的参数。