本教程适用于JDK 8。本页中描述的示例和实践不利用后续版本中引入的改进,并可能使用已不再可用的技术。
有关Java SE 9及后续版本中更新的语言功能的摘要,请参阅Java语言更改。
有关所有JDK版本的新功能、增强功能和已删除或弃用选项的信息,请参阅JDK发布说明。
你可以使用方法java.lang.reflect.Executable.getParameters
获取任何方法或构造函数的形式参数的名称。(类Method
和Constructor
扩展了类Executable
,因此继承了方法Executable.getParameters
。)但是,默认情况下,.class
文件不会存储形式参数的名称。这是因为许多生成和使用class文件的工具可能不期望包含参数名称的.class
文件的更大的静态和动态占用空间。特别是,这些工具将需要处理更大的.class
文件,并且Java虚拟机(JVM)将使用更多内存。此外,某些参数名称(例如secret
或password
)可能会暴露有关安全敏感方法的信息。
要将形式参数名称存储在特定的.class
文件中,从而使反射API能够检索形式参数名称,请使用javac
编译器的-parameters
选项编译源文件。
示例
演示了如何检索给定类的所有构造函数和方法的形式参数的名称。该示例还打印有关每个参数的其他信息。MethodParameterSpy
以下命令打印类
的构造函数和方法的形式参数名称。 注意:记得使用ExampleMethods
-parameters
编译器选项编译示例ExampleMethods
:
java MethodParameterSpy ExampleMethods
此命令打印以下内容:
构造函数的数量:1 构造函数 #1 public ExampleMethods() 声明的构造函数数量:1 声明的构造函数 #1 public ExampleMethods() 方法的数量:4 方法 #1 public boolean ExampleMethods.simpleMethod(java.lang.String,int) 返回类型:boolean 泛型返回类型:boolean 参数类型:class java.lang.String 参数名称:stringParam 修饰符:0 是否隐式?:false 是否存在名称?:true 是否合成?:false 参数类型:int 参数名称:intParam 修饰符:0 是否隐式?:false 是否存在名称?:true 是否合成?:false 方法 #2 public int ExampleMethods.varArgsMethod(java.lang.String...) 返回类型:int 泛型返回类型:int 参数类型:class [Ljava.lang.String; 参数名称:manyStrings 修饰符:0 是否隐式?:false 是否存在名称?:true 是否合成?:false 方法 #3 public boolean ExampleMethods.methodWithList(java.util.List<java.lang.String>) 返回类型:boolean 泛型返回类型:boolean 参数类型:interface java.util.List 参数名称:listParam 修饰符:0 是否隐式?:false 是否存在名称?:true 是否合成?:false 方法 #4 public <T> void ExampleMethods.genericMethod(T[],java.util.Collection<T>) 返回类型:void 泛型返回类型:void 参数类型:class [Ljava.lang.Object; 参数名称:a 修饰符:0 是否隐式?:false 是否存在名称?:true 是否合成?:false 参数类型:interface java.util.Collection 参数名称:c 修饰符:0 是否隐式?:false 是否存在名称?:true 是否合成?:false
MethodParameterSpy
示例使用了Parameter
类中的以下方法:
getType
:返回一个标识参数声明类型的Class
对象。
getName
:返回参数的名称。如果参数的名称存在,则该方法返回.class
文件提供的名称。否则,该方法会合成一个形式为argN
的名称,其中N
是声明该参数的方法描述符中参数的索引。
例如,假设您在未指定-parameters
编译器选项的情况下编译了ExampleMethods
类。对于方法ExampleMethods.simpleMethod
,示例MethodParameterSpy
将打印以下内容:
public boolean ExampleMethods.simpleMethod(java.lang.String,int) 返回类型:boolean 泛型返回类型:boolean 参数类:class java.lang.String 参数名称:arg0 修饰符:0 是否隐式:false 是否存在名称:false 是否合成:false 参数类:int 参数名称:arg1 修饰符:0 是否隐式:false 是否存在名称:false 是否合成:false
getModifiers
:返回表示形式参数具有的各种特性的整数。该值是以下值的和,如果适用于形式参数:
值(十进制) | 值(十六进制) | 描述 |
---|---|---|
16 | 0x0010 | 形式参数声明为final |
4096 | 0x1000 | 形式参数是合成的。或者,您可以调用方法isSynthetic 。 |
32768 | 0x8000 | 参数在源代码中隐式声明。或者,您可以调用方法isImplicit |
isImplicit
:如果该参数在源代码中是隐式声明的,则返回true
。有关更多信息,请参见隐式和合成参数部分。
isNamePresent
:如果该参数在.class
文件中具有名称,则返回true
。
isSynthetic
:如果该参数在源代码中既不是隐式声明的也不是显式声明的,则返回true
。有关更多信息,请参见隐式和合成参数部分。
如果某些构造在源代码中没有显式地声明,那么它们会被隐式地声明。例如,
示例中没有包含构造函数。默认构造函数会被隐式地声明。ExampleMethods
MethodParameterSpy
示例会打印关于ExampleMethods
的隐式声明构造函数的信息:
声明的构造函数数量:1 public ExampleMethods()
考虑以下来自
的摘录:MethodParameterExamples
public class MethodParameterExamples { public class InnerClass { } }
类InnerClass
是一个非静态的嵌套类或内部类。内部类也会被隐式地声明一个构造函数,但是这个构造函数会包含一个参数。当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) 参数类: class MethodParameterExamples 参数名称: this$0 修饰符: 32784 是否隐式: true 是否存在名称: true 是否合成的: false
因为InnerClass
的构造函数是隐式声明的,所以它的参数也是隐式的。
注意:
InnerClass
构造函数的参数既是final(16),又是隐式的(32768)。$
),但按照惯例,变量名中不使用美元符号。Java编译器生成的构造函数被标记为合成的,如果它们不对应于源代码中明确或隐式声明的构造函数,除非它们是类初始化方法。合成的构造函数是由编译器生成的在不同实现之间可能会有所不同的构造函数。考虑下面的示例来自
:MethodParameterExamples
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编译器可能为其指定不同的形式参数。当编译器编译使用enum
常量的表达式时,它们仅依赖于enum
构造函数的public static字段,这些字段是隐式声明的,而不依赖于它们的构造函数或这些常量的初始化方式。)
因此,示例MethodParameterExample
关于enum
构造函数Colors
的输出如下:
枚举类型 Colors: 构造函数数量:0 已声明的构造函数数量:1 已声明的构造函数 #1 private MethodParameterExamples$Colors() 参数类:class java.lang.String 参数名:$enum$name 修饰符:4096 是否隐式声明?:false 名称是否存在?:true 是否合成的?:true 参数类:int 参数名:$enum$ordinal 修饰符:4096 是否隐式声明?:false 名称是否存在?:true 是否合成的?:true 方法数量:2 方法 #1 public static MethodParameterExamples$Colors[] MethodParameterExamples$Colors.values() 返回类型:class [LMethodParameterExamples$Colors; 泛型返回类型:class [LMethodParameterExamples$Colors; 方法 #2 public static MethodParameterExamples$Colors MethodParameterExamples$Colors.valueOf(java.lang.String) 返回类型:class MethodParameterExamples$Colors 泛型返回类型:class MethodParameterExamples$Colors 参数类:class java.lang.String 参数名:name 修饰符:32768 是否隐式声明?:true 名称是否存在?:true 是否合成的?:false
有关隐式声明的构造的更多信息,请参阅Java语言规范,包括在反射API中隐式出现的参数。