MethodParameters是JDK8加入的新属性,为了记录方法入参的名字和访问标志信息。之后可通过反射拿到方法的原始参数名,而不是var0、var1这种。
在class里结构
MethodParameters属于属性信息,它的结构如下:
类型 | 名称 | 数量 |
---|---|---|
u2 | attribute_name_index | 1 |
u4 | attribute_lenght | 1 |
u1 | parameters_count | 1 |
parameter | parameters | parameters_count |
parameter:
类型 | 名称 | 数量 |
---|---|---|
u2 | name_index | 1 |
u2 | access_flags | 1 |
参数介绍
- u1代表1个字节,u2代表2个字节,一次类推。
- attribute_name_index是指向常量池里CONSTANT_Utf8_info类型的索引值,对应值是MethodParameters
- attribute_lenght代表属性值占用的长度
- parameters_count代表参数parameters的个数
- parameter.name_index是指向常量池里CONSTANT_Utf8_info类型的索引值,也就是参数名
- parameter.access_flags是参数的状态指示器,标记参数是否被final修饰(0x0010);表示参数是否是编译器自动生成(0x1000);表示参数是否是隐士定义(0x8000),例如this关键字。
如何生成MethodParameters
通过javac的parameters参数,开启MethodParameters
javac -parameters ParameterTest.java
public class ParameterTest {
public static void test(final String name, int age) {
System.out.println("name: " + name + ", age: " + age);
}
public static void main(String[] args) throws NoSuchMethodException {
for (Parameter parameter : ParameterTest.class.getMethod("test", String.class, int.class).getParameters()) {
System.out.println("Parameter: " + parameter.getName());
}
}
}
然后通过javap命令查看class文件
javap -v ParameterTest.class
public static void test(java.lang.String, int);
descriptor: (Ljava/lang/String;I)V
flags: ACC_PUBLIC, ACC_STATIC
Code:
stack=3, locals=2, args_size=2
0: getstatic #2 // Field java/lang/System.out:Ljava/io/PrintStream;
3: new #3 // class java/lang/StringBuilder
6: dup
7: invokespecial #4 // Method java/lang/StringBuilder."<init>":()V
10: ldc #5 // String name:
12: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
15: aload_0
16: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
19: ldc #7 // String , age:
21: invokevirtual #6 // Method java/lang/StringBuilder.append:(Ljava/lang/String;)Ljava/lang/StringBuilder;
24: iload_1
25: invokevirtual #8 // Method java/lang/StringBuilder.append:(I)Ljava/lang/StringBuilder;
28: invokevirtual #9 // Method java/lang/StringBuilder.toString:()Ljava/lang/String;
31: invokevirtual #10 // Method java/io/PrintStream.println:(Ljava/lang/String;)V
34: return
LineNumberTable:
line 11: 0
line 12: 34
MethodParameters:
Name Flags
name final
age
MethodParameters属性在方法的最后面,包含name和age两个变名,name的Flags是final。
通过反射获取MethodParameters信息
通过Class的getMethod获取到Method对象后,就可通过getParameters()方法获取到Parameter对象,里面包含了变量名信息。具体代码在ParameterTest的main()方法里展示了。
Maven自动打包参数名
一般我们不会直接使用javac编译代码,而是使用maven进行打包。使用maven-compiler-plugin可以帮我们配置编译的参数,在<compilerArgs>里配置上-parameters就能自动生效:
<plugin>
<groupId>org.apache.maven.plugins</groupId>
<artifactId>maven-compiler-plugin</artifactId>
<configuration>
<source>1.8</source>
<target>1.8</target>
<compilerArgs>
<compilerArg>-parameters</compilerArg>
</compilerArgs>
</configuration>
</plugin>
如果maven版本≥3.6.2,也可以用<parameters>true</parameters>代替<compilerArgs>的方式。