参考材料
- https://github.com/LRH1993/android_interview/blob/master/java/basis/java-8.md 的 3.1 小节
-
https://docs.oracle.com/javase/8/docs/technotes/tools/windows/javac.html 中的
-parameters
部分
javac 命令的 -parameters 选项 -
https://docs.oracle.com/javase/specs/jvms/se8/html/jvms-4.html#jvms-4.7.24 对
MethodParameters
属性的描述
原理简述
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
文件的结构是一个比较大的话题(且本文作者水平有限,也只知道个大概),这里就不多说了。相关结果截图如下
另外,如果编译时没有写 -parameters
选项的话,编译时的命令就会是
# 这样是看不到参数名称的
javac Show.java
仍旧使用如下命令运行得到的 class
文件
java -cp . Show
这样就只能看到 arg0
arg1
这样的变量名了。运行效果示意图如下
我在
java.lang.reflect.Parameter
中看到了如下的一段话,可以解释为何现在看到的变量名是 arg0
和 arg1
看一下
getName()
的源码(如下图),会发现,当 name
为 null
或 ""
时,返回值就会是 argN
这种样子的。javap -cp . -v -p Show
此时如果使用上述命令分析 class
文件,会发现之前看到的 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
相关结果截图如下