反射
通俗的说就是你对象不管做的多么的严谨,只要通过反射就好比一面镜子,把你的对象拷过来,并且拷过来的对象,是任由我宰割的。
下面就简单的举个栗子:
第一步:创建要反射的对象:
这里我就写个超级简单的Student
类,里面没有什么东西,2个属性。和一个私有的方法。
package javaClass;
public class Student {
private String name;
private int age;
private Student() {
super();
}
public Student(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;
}
private String studentInfo() {
return "我的名字是:"+name;
}
}
- 有2个构造函数,一个是私有的,一个是公共的
- 属性也是私有的哦
- 其他都是get、set方法,就不说明了
- 最后一个
studentInfo
方法是私有的
目的
我们要用反射,把
Student
类用私有的构造函数创建出来,并且不通过set方法给属性赋值。还要调用私有的studentInfo
方法,看起来很酷!
第二步:获取字节码
- 首先获取
Student
字节码
第一种方式:
Class clazz = Class.forName("javaClass.Student");
第二种方式:
Class clazz=Student.class;
第三种方式:
Student student = new Student();
Class clazz=student.getClass();
一般用第一种方式,最后一种方式,你都能创建对象了,你还用放射,明显是人才。第二种需要引入包名,而最第一种只需要字符串
第三步:创建对象
有了字节码,我们就等于拿到了克隆后的对象,现在怎么折腾都是由我们自己决定,现在我们要用私有的构造函数,来创建对象。
//获取无参的私有构造函数
Constructor cons = clazz.getDeclaredConstructor();
//设置无视jvm规则
cons.setAccessible(true);
//创建对象
Object newInstance= cons.newInstance();
//查看是否是Student对象
System.out.println(newInstance instanceof Student);
输出结果:true
第四步:设置字段
//通过字节码获取所有字段
Field[] fields = clazz.getDeclaredFields();
//遍历所有的字段
for (Field field : fields) {
//设置暴力
field.setAccessible(true);
//如果为年龄字段的话,就设置为整形
if(field.getName().equals("age")) {
field.set(newInstance, 23);
}else {
//这个对象就2个属性,那这个是放字符串的
field.set(newInstance, "刘德华");
}
}
Student s=(Student)newInstance;
System.out.println(s.getName());
System.out.println(s.getAge());
输出结果:刘德华、23
第五步:调用私有方法
我觉得这个操作最短,看代码:
//获取studentInfo方法
//这getDeclaredMethod方法有2个参数,一个参数为:方法名,第二参数是:该方法需要传入的参数
//因为我们的studentInfo不需要传参,所有第二个参数就不需要填写
Method method = clazz.getDeclaredMethod("studentInfo");
//暴力设置
method.setAccessible(true);
//调用,返回一个结果
Object invoke = method.invoke(newInstance);
//看结果咯
System.out.println(invoke);
输出结果:我的名字是:刘德华