Skip to content

Commit 954966a

Browse files
authored
Create 通过反射获得方法的参数信息.md
- 与README.md同步
1 parent dfa0772 commit 954966a

File tree

1 file changed

+79
-0
lines changed

1 file changed

+79
-0
lines changed
Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,79 @@
1+
##              通过反射获得方法的参数信息
2+
JDK8之前 .class文件是不会存储方法参数信息的,因此也就无法通过反射获取该信息(想想反射获取类信息的入口是什么?当然就是Class类了)。即是是在JDK11里
3+
也不会默认生成这些信息,可以通过在javac加上-parameters参数来让javac生成这些信息(javac就是java编译器,可以把java文件编译成.class文件)。生成额外
4+
的信息(运行时非必须信息)会消耗内存并且有可能公布敏感信息(某些方法参数比如password,JDK文档里这么说的),并且确实很多信息javac并不会为我们生成,比如
5+
LocalVariableTable,javac就不会默认生成,需要你加上 -g:vars来强制让编译器生成,同样的,方法参数信息也需要加上
6+
-parameters来让javac为你在.class文件中生成这些信息,否则运行时反射是无法获取到这些信息的。在讲解Java语言层面的方法之前,先看一下javac加上该
7+
参数和不加生成的信息有什么区别(不感兴趣想直接看运行代码的可以跳过这段)。下面是随便写的一个类。
8+
```java
9+
public class ByteCodeParameters {
10+
public String simpleMethod(String canUGetMyName, Object yesICan) {
11+
return "9527";
12+
}
13+
}
14+
```
15+
先来不加参数编译和反编译一下这个类javac ByteCodeParameters.java , javap -v ByteCodeParameters:
16+
```java
17+
//只截取了部分信息
18+
public java.lang.String simpleMethod(java.lang.String, java.lang.Object);
19+
descriptor: (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;
20+
flags: (0x0001) ACC_PUBLIC
21+
Code:
22+
stack=1, locals=3, args_size=3
23+
0: ldc #2 // String 9527
24+
2: areturn
25+
LineNumberTable:
26+
line 5: 0
27+
//这个方法的描述到这里就结束了
28+
```
29+
接下来我们加上参数javac -parameters ByteCodeParameters.java 再来看反编译的信息:
30+
```java
31+
public java.lang.String simpleMethod(java.lang.String, java.lang.Object);
32+
descriptor: (Ljava/lang/String;Ljava/lang/Object;)Ljava/lang/String;
33+
flags: (0x0001) ACC_PUBLIC
34+
Code:
35+
stack=1, locals=3, args_size=3
36+
0: ldc #2 // String 9527
37+
2: areturn
38+
LineNumberTable:
39+
line 8: 0
40+
MethodParameters:
41+
Name Flags
42+
canUGetMyName
43+
yesICan
44+
```
45+
可以看到.class文件里多了一个MethodParameters信息,这就是参数的名字,可以看到默认是不保存的。
46+
<br>下面看一下在Intelj Idea里运行的这个例子,我们试一下通过反射获取方法名 :
47+
```java
48+
public class ByteCodeParameters {
49+
public String simpleMethod(String canUGetMyName, Object yesICan) {
50+
return "9527";
51+
}
52+
53+
public static void main(String[] args) throws NoSuchMethodException {
54+
Class<?> clazz = ByteCodeParameters.class;
55+
Method simple = clazz.getDeclaredMethod("simpleMethod", String.class, Object.class);
56+
Parameter[] parameters = simple.getParameters();
57+
for (Parameter p : parameters) {
58+
System.out.println(p.getName());
59+
}
60+
}
61+
}
62+
输出 :
63+
arg0
64+
arg1
65+
```
66+
???说好的方法名呢????别急,哈哈。前面说了,默认是不生成参数名信息的,因此我们需要做一些配置,我们找到IDEA的settings里的Java Compiler选项,在
67+
Additional command line parameters:一行加上-parameters(Eclipse 也是找到Java Compiler选中Stoer information about method parameters),或者自
68+
己编译一个.class文件放在IDEA的out下,然后再来运行 :
69+
```java
70+
输出 :
71+
canUGetMyName
72+
yesICan
73+
```
74+
这样我们就通过反射获取到参数信息了。想要了解更多的同学可以自己研究一下 [官方文档]
75+
(https://docs.oracle.com/javase/tutorial/reflect/member/methodparameterreflection.html)
76+
<br>
77+
## 总结与补充
78+
在JDK8之后,可以通过-parameters参数来让编译器生成参数信息然后在运行时通过反射获取方法参数信息,其实在SpringFramework
79+
里面也有一个LocalVariableTableParameterNameDiscoverer对象可以获取方法参数名信息,有兴趣的同学可以自行百度(这个类在打印日志时可能会比较有用吧,个人感觉)。

0 commit comments

Comments
 (0)