1
0
mirror of https://github.com/Snailclimb/JavaGuide synced 2025-06-20 22:17:09 +08:00

Create 通过反射获得方法的参数信息.md

- 与README.md同步
This commit is contained in:
haiqiang 2019-03-12 23:43:39 +08:00 committed by GitHub
parent dfa077245b
commit 954966afc4
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23

View File

@ -0,0 +1,79 @@
##              通过反射获得方法的参数信息
JDK8之前 .class文件是不会存储方法参数信息的因此也就无法通过反射获取该信息(想想反射获取类信息的入口是什么当然就是Class类了)。即是是在JDK11里
也不会默认生成这些信息可以通过在javac加上-parameters参数来让javac生成这些信息(javac就是java编译器可以把java文件编译成.class文件)。生成额外
的信息(运行时非必须信息)会消耗内存并且有可能公布敏感信息(某些方法参数比如passwordJDK文档里这么说的)并且确实很多信息javac并不会为我们生成比如
LocalVariableTablejavac就不会默认生成需要你加上 -g:vars来强制让编译器生成同样的方法参数信息也需要加上
-parameters来让javac为你在.class文件中生成这些信息否则运行时反射是无法获取到这些信息的。在讲解Java语言层面的方法之前先看一下javac加上该
参数和不加生成的信息有什么区别(不感兴趣想直接看运行代码的可以跳过这段)。下面是随便写的一个类。
```java
public class ByteCodeParameters {
public String simpleMethod(String canUGetMyName, Object yesICan) {
return "9527";
}
}
```
先来不加参数编译和反编译一下这个类javac ByteCodeParameters.java , javap -v ByteCodeParameters:
```java
//只截取了部分信息
public java.lang.String simpleMethod(java.lang.String, java.lang.Object);
descriptor: (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=3, args_size=3
0: ldc #2 // String 9527
2: areturn
LineNumberTable:
line 5: 0
//这个方法的描述到这里就结束了
```
接下来我们加上参数javac -parameters ByteCodeParameters.java 再来看反编译的信息:
```java
public java.lang.String simpleMethod(java.lang.String, java.lang.Object);
descriptor: (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;
flags: (0x0001) ACC_PUBLIC
Code:
stack=1, locals=3, args_size=3
0: ldc #2 // String 9527
2: areturn
LineNumberTable:
line 8: 0
MethodParameters:
Name Flags
canUGetMyName
yesICan
```
可以看到.class文件里多了一个MethodParameters信息这就是参数的名字可以看到默认是不保存的。
<br>下面看一下在Intelj Idea里运行的这个例子我们试一下通过反射获取方法名 :
```java
public class ByteCodeParameters {
public String simpleMethod(String canUGetMyName, Object yesICan) {
return "9527";
}
public static void main(String[] args) throws NoSuchMethodException {
Class<?> clazz = ByteCodeParameters.class;
Method simple = clazz.getDeclaredMethod("simpleMethod", String.class, Object.class);
Parameter[] parameters = simple.getParameters();
for (Parameter p : parameters) {
System.out.println(p.getName());
}
}
}
输出 :
arg0
arg1
```
说好的方法名呢别急哈哈。前面说了默认是不生成参数名信息的因此我们需要做一些配置我们找到IDEA的settings里的Java Compiler选项
Additional command line parameters:一行加上-parameters(Eclipse 也是找到Java Compiler选中Stoer information about method parameters),或者自
己编译一个.class文件放在IDEA的out下然后再来运行 :
```java
输出 :
canUGetMyName
yesICan
```
这样我们就通过反射获取到参数信息了。想要了解更多的同学可以自己研究一下 [官方文档]
(https://docs.oracle.com/javase/tutorial/reflect/member/methodparameterreflection.html)
<br>
## 总结与补充
在JDK8之后可以通过-parameters参数来让编译器生成参数信息然后在运行时通过反射获取方法参数信息其实在SpringFramework
里面也有一个LocalVariableTableParameterNameDiscoverer对象可以获取方法参数名信息有兴趣的同学可以自行百度(这个类在打印日志时可能会比较有用吧,个人感觉)。