本教程适用于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
是否合成:falsegetModifiers:返回表示形式参数具有的各种特性的整数。该值是以下值的和,如果适用于形式参数:
| 值(十进制) | 值(十六进制) | 描述 |
|---|---|---|
| 16 | 0x0010 | 形式参数声明为final |
| 4096 | 0x1000 | 形式参数是合成的。或者,您可以调用方法isSynthetic。 |
| 32768 | 0x8000 | 参数在源代码中隐式声明。或者,您可以调用方法isImplicit |
isImplicit:如果该参数在源代码中是隐式声明的,则返回true。有关更多信息,请参见隐式和合成参数部分。
isNamePresent:如果该参数在.class文件中具有名称,则返回true。
isSynthetic:如果该参数在源代码中既不是隐式声明的也不是显式声明的,则返回true。有关更多信息,请参见隐式和合成参数部分。
如果某些构造在源代码中没有显式地声明,那么它们会被隐式地声明。例如,示例中没有包含构造函数。默认构造函数会被隐式地声明。ExampleMethodsMethodParameterSpy示例会打印关于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中隐式出现的参数。