什么是反射
在运行状态中,对于任意一个的类,都能通过反射知道或者获取这个类的所有属性和方法,不管是public还是private。反射能把Java类钟的各种成分映射成一个个Java对象,本质就是获取类的字节码文件,即.class文件,获取/调用类的属性或者方法。
重要方法
获取构造方法
方法 | 功能描述 |
---|---|
public Constructor getConstructor(Class<?>… parameterTypes) | 获取指定的构造方法,但是只能获得public权限的构造方法 |
public Constructor getDeclaredConstructor(Class<?>… parameterTypes) | 获取指定的构造方法,包括private和protected |
public Constructor<?>[] getConstructors() throws SecurityException | 获取所用的public定义的构造方法,返回的是集合 |
public Constructor<?>[] getDeclaredConstructors() throws SecurityException | 真正意义上获取所有的构造方法,包括private和protected,返回的是集合 |
获取属性及方法
方法 | 功能描述 |
---|---|
public Field[] getFields() | 获取所有public权限的属性 |
public Field getField(String name) | 获取指定的属性 |
public native Field[] getDeclaredFields() | 获取所有的属性,包括private和protected的属性集合 |
public Method[] getMethods() | 获取所有public权限的方法 |
public Method getMethod(String name, Class<?>… parameterTypes) | 获取指定的方法 |
public Method[] getDeclaredMethods() | 获取所有的属性,包括private和protected的方法集合 |
综上可以看出方法名尾缀有s的返回都是集合,有Declared的都是能获取所有属性或是方法。
反射具体实现
测试属性和构造方法
定义一个Person类1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21public class Person {
public String name;
private int id;
public Person() {
System.out.println("无参构造方法");
}
private Person(String name, int id) {
this.id = id;
this.name = name;
}
private void eat() {
System.out.println("private-------------eat");
}
public void drink() {
System.out.println("public-------------drink");
}
}
使用测试1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52//三种获取Class对象的方式
Person person = new Person();
Class c1 = person.getClass();
Class c2 = Person.class;
Class c3 = Class.forName("com.zhouk.roomlocaltion.MainActivityTest.Person");
//获得类完整的名字
String className = c2.getName();
System.out.println("className:"+className);//输出com.ys.reflex.Person
//获得类的public类型的属性。
Field[] fields = c2.getFields();
for (Field field : fields) {
System.out.println("public属性:"+field.getName());
}
//获得类的所有属性。包括私有的
Field[] allFields = c2.getDeclaredFields();
for (Field field : allFields) {
System.out.println("全部属性:"+field.getName());
}
//获得类的public类型的方法。这里包括 Object 类的一些方法
Method[] methods = c2.getMethods();
for (Method method : methods) {
System.out.println("public方法:"+method.getName());//work waid equls toString hashCode等
}
//获得类的所有方法。
Method[] allMethods = c2.getDeclaredMethods();
for (Method method : allMethods) {
System.out.println("全部方法:"+method.getName());//work say
}
//获得指定的public属性
Field f1 = c2.getField("name");
System.out.println("获取name属性:"+f1);
//获得指定的私有属性
Field f2 = c2.getDeclaredField("id");
//启用和禁用访问安全检查的开关,值为 true,则表示反射的对象在使用时应该取消 java 语言的访问检查;反之不取消
f2.setAccessible(true);
System.out.println("获取id属性:"+f2);
//获取构造方法
Constructor[] constructors = c2.getDeclaredConstructors();
for (Constructor constructor : constructors) {
System.out.println("获取所有构造方法:"+constructor.toString());
}
可以看出无论私有还是公有,都可通过对应得方法来获取,那么利用反射如何调用私有方法呢?
用反射调用方法
1 | public class Person { |
需要注意得是,调用私有方法必须要method.setAccessible(true)来接触私有限制。
总结
可以看出在反射机制面前,类得私有变量、方法都能访问的到,通过反射我们可以业务关系解耦中发挥很大的作用,不暴露内部实现,又能拓展新业务,将开闭原则运用到极致,很多框架中的注解很中意使用反射。
另外再说下反射与private之间的矛盾,为什么Java允许private私有化变量或者方法禁止他类访问,而又出现反射机制来打破这种规定呢?其实对于private来讲,更大的意义是面向对象编程,它并不能解决安全的问题。一旦获取到代码,始终还是有办法查看或者改变代码的。表现安全更多的是无法让他人获取/查看代码。
所以,private比较类似生活中遇到的“禁止通行”的路标,但是脚在你腿上,你想走还是可以走的,但是后果就自负了。