参考材料
原理简述
java8 对应的 javac 命令支持 -parameters 选项。如果编译时启用该选项,构造函数和普通方法的参数名称会被保存到编译所得的 class 文件中。
参考材料[2] 中的原文如下
Stores formal parameter names of constructors and methods in the generated class file so that the method java.lang.reflect.Executable.getParameters from the Reflection API can retrieve them.
我们通过 jdk 提供的反射相关 api 就可以访问到这些参数名称了(由于相关信息已经保存在 class 文件里了,直接用 javap 分析 class 文件也能看到这些参数名)
实战
构造函数(constructors)和普通方法(methods)我各写一个例子来演示效果。
构造函数
代码
import java.lang.reflect.Constructor;
import java.lang.reflect.Parameter;
public class Show {
public static void main(String[] args) throws Exception {
// 找到那个构造函数
Constructor constructor = Show.class.getConstructor(int.class, Object.class);
for (Parameter parameter : constructor.getParameters()) {
System.out.println("参数名为: " + parameter.getName());
}
}
/**
* 由于不关心构造函数里的逻辑, 这个构造函数内就没有写任何代码
* 两个参数都相当于占位符
*
* @param firstPlaceHolderWithALongName 就是个展示符, 名字很长, 容易被看到
* @param secondPlaceHolder 也是一个占位符
*/
public Show(int firstPlaceHolderWithALongName, Object secondPlaceHolder) {
}
}
将上述代码保存为 Show.java。
编译
用如下命令对 Show.java 进行编译(注意:要加上 -parameters 选项才能看到效果)
javac -parameters Show.java
运行
用如下命令运行得到的 class 文件(注意不要加 .class 后缀名)
java -cp . Show
确认结果
结果如下
查看构造函数中各个参数的名称
如果直接用 javap 分析得到 Show.class 的话,也可以看到对应的参数名。
用到的命令如下
javap -cp . -v -p Show
完整的结果较长,class 文件的结构是一个比较大的话题(且本文作者水平有限,也只知道个大概),这里就不多说了。相关结果截图如下
在 MethodParameters 属性部分可以看到参数名称
另外,如果编译时没有写 -parameters 选项的话,编译时的命令就会是
# 这样是看不到参数名称的
javac Show.java
仍旧使用如下命令运行得到的 class 文件
java -cp . Show
这样就只能看到 arg0 arg1 这样的变量名了。运行效果示意图如下
只能看到自动生成的变量名
我在 java.lang.reflect.Parameter 中看到了如下的一段话,可以解释为何现在看到的变量名是 arg0 和 arg1
变量名为何是 arg0 arg1
看一下 getName() 的源码(如下图),会发现,当 name 为 null 或 "" 时,返回值就会是 argN 这种样子的。
getName() 方法的源码
javap -cp . -v -p Show
此时如果使用上述命令分析 class 文件,会发现之前看到的 MethodParameters 属性也不见了
MethodParameters 属性消失
普通方法
代码
import java.lang.reflect.Method;
import java.lang.reflect.Parameter;
public class Show {
public static void main(String[] args) throws Exception {
// 找到那个函数
Method method = Show.class.getDeclaredMethod("dummy", int.class, Object.class);
for (Parameter parameter : method.getParameters()) {
System.out.println("参数名为: " + parameter.getName());
}
}
/**
* 由于不关心这个函数里的逻辑, 此函数内就没有写任何代码
* 两个参数都相当于占位符
*
* @param firstPlaceHolderWithALongName 就是个展示符, 名字很长, 容易被看到
* @param secondPlaceHolder 也是一个占位符
*/
private void dummy(int firstPlaceHolderWithALongName, Object secondPlaceHolder) {
}
}
编译
用如下命令对 Show.java 进行编译
javac -parameters Show.java
运行
用如下命令运行得到的 class 文件
java -cp . Show
确认结果
结果如下
查看普通方法中各个参数的名称
如果直接用 javap 分析得到 Show.class 的话,也可以看到对应的参数名。
用到的命令如下
javap -cp . -v -p Show
相关结果截图如下
在 MethodParameters 属性部分可以看到参数名称