你对反射的理解
- 应用在一些通用性较高的代码中
- 框架的底层基于反射
- 在框架开发中,都是基于配置文件开发,在配置文件中配置子类,可以通过反射得到类中的所有内容,可以让类中的某个方法执行
- 类中的所有内容:属性、没有参数的构造方法、有参数的构造方法、普通方法,都可以通过反射机制动态获得。
提出问题
那么接下来就看看怎么通过反射来获得类中的内容,首先了解一个类的加载过程:
1.编写类的源码,保存到硬盘;
2.编译成class文件;
3.把class文件加载到内存通过JVM执行。
所以,只要得到了这个class,我们就可以得到这个类的所有内容。
准备工作
首先,我们建立一个Person类,有name和age两个属性,有参数和无参数的构造函数还有封装属性的基本方法:
package jimo.reflect;
public class Person {
//属性
private String name;
private int age;
//无参和有参构造函数
public Person(){
}
public Person(String name, int age) {
super();
this.name = name;
this.age = age;
}
//普通方法
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
}
首先,了解通过反射获得类有三种方式:
方式1:类名.class
方式2:对象.getClass()
方式3:Class.forName(“路径”)
用代码看起来就是这样:
public static void main(String[] args) throws ClassNotFoundException {
Class c1 = Person.class;
Class c2 = new Person().getClass();
Class c3 = Class.forName("jimo.reflect.Person");
}
注意:路径包括包名,copy小技巧:在类名上右键:
实现代码
现在可以来获得类的属性,构造方法,普通方法了。
1 . 用反射获取对象实例,不用new:
public void getInstance() throws ClassNotFoundException, InstantiationException, IllegalAccessException{
Class c = Class.forName("jimo.reflect.Person");
Person p = (Person) c.newInstance();
}
2 . 用反射获取类的属性:
public void getField() throws ClassNotFoundException, NoSuchFieldException, SecurityException, InstantiationException, IllegalAccessException{
Class c = Class.forName("jimo.reflect.Person");
Person p = (Person) c.newInstance();
Field f = c.getDeclaredField("age");//参数为属性名称
f.setAccessible(true);//设置可以访问私有属性
try {
f.set(p,20);//第一个参数为Person对象,第二个参数为设置的属性的值
System.out.println(f.get(p));
} catch (IllegalArgumentException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
3 . 通过反射操作有参构造函数:
为什么是有参呢?因为无参已经做过了。
public void testConstruct() throws Exception{
Class c = Class.forName("jimo.reflect.Person");
Constructor cs = c.getConstructor(String.class,int.class);//注意这个可变参数
Person p = (Person) cs.newInstance("jimo",20);
p.setAge(10);
System.out.println(p.getAge());//结果10
}
4 . 反射操作普通方法:
public void testMethod() throws Exception{
Class c = Class.forName("jimo.reflect.Person");
Person p = (Person) c.newInstance();
Method md = c.getDeclaredMethod("setName", String.class);//第一个参数为方法名称,第二个是可变参数,为方法的参数类
//md.setAccessible(true);
md.invoke(p, "jimo");
Method md2 = c.getDeclaredMethod("getName");
System.out.println(md2.invoke(p));//结果为jimo
}
那如果普通方法是静态的怎么做呢?很简单,因为静态方法直接由类调用,不通过实例,所以invoke第一个参数填 null 就好。
可以看到:
1. .setAccessible(true);这个方法可以使私有属性和方法被访问,相当于失去了封装的效果。
2. 我们很少用到反射来获取实例,着重理解反射的原理。