一、反射概述
- 反射概述
- 反射是指对于任何一个Class类,在“运行的时候”都可以直接得到这个类的全部成分
- 在运行时,可以直接得到这个类的构造器对象:Construcor
- 在运行时,可以直接得到这个类的构造器对象:Field
- 在运行时,可以直接得到这个类的构造器对象:Method
- 这种运行时动态获取类信息以及动态调用类中成分的能力称为Java语言的反射机制
- 反射的关键
- 反射的第一步都是先得到编译后的Class类对象,然后就可以得到Class的全部成分
HelloWorld.java -> javac -> HelloWorld.class
Class c = HelloWorld.class
二、反射获取类对象
- forName(String className)
- 类名.class
- 对象.getClass()
/**
* 获取class对象
*/
public class Test {
public static void main(String[] args) throws Exception {
// 1、Class类中的静态方法:forName
Class c = Class.forName("reflect.Student");
System.out.println(c);
// 2、类名.class
Class c1 = Student.class;
System.out.println(c1);
// 3、对象.getClass()
Student s = new Student();
Class c2 = s.getClass();
System.out.println(c2);
}
}
三、反射获取构造器对象
- 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象
- Class类中用于获取构造器的方法
- Constructor<>[] getConstructors():返回所有构造器对象的数组(只能拿public)
- Constructor<>[] getDeclaredConstructors():返回所有构造器对象的数组
- Constructor getConstructor(Class<?>… parameterTypes):返回单个构造器对象(只能拿public)
- Constructor getDeclaredConstructor(Class<?>… parameterTypes):返回单个构造器对象
public class TestStudent01 {
@Test
public void getConstructors(){
// a.第一步:获取类对象
Class c = Student.class;
// b.提取类中的全部构造器对象
Constructor[] constructors = c.getConstructors();
// c.遍历构造器
for (Constructor constructor : constructors) {
System.out.println(constructor.getName() + "====>" + constructor.getParameterCount());
}
}
}
- 获取构造器的作用是初始化一个对象返回
- T newInstance(Object… initargs):根据指定的构造器创建对象
- public void setAccessible(boolean flag):设置为true,表示取消访问检查,进行暴力反射
四、反射获得成员变量对象
- 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象
- Class类中用于获取成员变量的方法
- Field[] getFields():返回所有成员变量对象的数组(只能拿public的)
- Field[] getDeclaredFields():返回所有成员变量对象的数组
- Field[] getField(String name):返回单个成员变量对象(只能拿public的)
- Field[] getDeclaredField(String name):返回单个成员变量对象
- Field类中用于取值、赋值的方法
- void set(Object obj,Object obj):赋值
- Object get(Object obj):获取值
public class Test {
@org.junit.Test
public void getDeclaredFields() throws Exception {
// a.获取类对象
Class c = Student.class;
// b.提取某个成员变量
Field ageF = c.getDeclaredField("age");
// c.赋值
ageF.setAccessible(true);//暴力打开权限
Student s = new Student();
ageF.set(s,18);
System.out.println(s);
}
}
五、反射获取方法对象
- 反射的第一步是先得到类对象,然后从类对象中获取类的成分对象
- Class类中用于获取成员变量的方法
- Method[] getMethods():返回所有成员方法对象的数组(只能拿public的)
- Method[] getDeclaredMethods():返回所有成员方法对象的数组
- Method getField(String name,Class):返回单个成员方法对象(只能拿public的)
- Method getDeclaredField(String name,Class):返回单个成员方法对象
- Field类中用于触发执行的方法
- Object invoke(Object obj,Object…args)
public class Test {
@org.junit.Test
public void getDeclaredMethods() throws Exception {
// a.获取类对象
Class c = Dog.class;
// b.提取单个方法
Method m = c.getDeclaredMethod("eat");
Method m2 = c.getDeclaredMethod("eat",String.class);
m.setAccessible(true);
m2.setAccessible(true);
// c.触发方法的执行
Dog d = new Dog();
Object result = m.invoke(d);
System.out.println(result);
Object result2 = m2.invoke(d,"骨头");
System.out.println(result2);
}
}
六、反射的作用-绕过编译阶段为集合添加数据(泛型擦除)
- 反射是作用在运行时的技术,此时集合的泛型将不能产生约束了,此时可以为集合存入其他任意类型的元素
- 泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成Class文件进入运行阶段的时候,其真实类型都是ArrayList,泛型相当于被擦除了
public class Demo {
public static void main(String[] args) throws Exception {
ArrayList<Integer> list = new ArrayList<>();
Class c = list.getClass();
Method add = c.getDeclaredMethod("add",Object.class);
add.invoke(list,"Roger");
System.out.println(list);
}
}
七、反射的作用-通用框架的底层原理
- 需求
- 任意一个对象,在不清楚对象字段的情况下,把对象的字段名称和对应值存储到文件中去
- 分析
- 定义一个方法,可以接收任意类的对象
- 每次收到一个对象后,需要解析这个对象的全部成员变量名称
- 这个对象可能是任意的
- 通过反射获取对象的Class类对象,然后获取全部成员变量信息
- 遍历成员变量信息,然后提取本成员变量在对象中的具体值
- 存入成员变量名称和值到文件中
Demo.java
/**
* 目标:提供一个通用框架,支持保存所有对象的具体信息
*/
public class Demo {
public static void main(String[] args) {
Student s = new Student("小明",'男',10,"三年二班","乒乓球");
MybatisUtil.save(s);
Teacher t = new Teacher("小红",'女',3000);
MybatisUtil.save(t);
}
}
Student.java
public class Student {
private String name;
private char sex;
private int age;
private String className;
private String hobby;
public Student() {
}
public Student(String name, char sex, int age, String className, String hobby) {
this.name = name;
this.sex = sex;
this.age = age;
this.className = className;
this.hobby = hobby;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public int getAge() {
return age;
}
public void setAge(int age) {
this.age = age;
}
public String getClassName() {
return className;
}
public void setClassName(String className) {
this.className = className;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
}
Teacher.java
public class Teacher {
private String name;
private char sex;
private double salary;
public Teacher() {
}
public Teacher(String name, char sex, double salary) {
this.name = name;
this.sex = sex;
this.salary = salary;
}
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public char getSex() {
return sex;
}
public void setSex(char sex) {
this.sex = sex;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
}
MybatisUtil.java
public class MybatisUtil {
public static void save(Object obj){
try {
PrintStream ps = new PrintStream(new FileOutputStream("E:/自学/project/IdeaProjects/file/junit-reflect-annotation-proxy/src/data.txt",true));
// 1、获取类对象
Class c = obj.getClass();
ps.println("========" + c.getSimpleName() + "========");
// 2、提取这个对象的全部成员变量
Field[] fields = c.getDeclaredFields();
// 3.获取成员变量信息
for (Field field : fields) {
String name = field.getName();
// 提取本成员变量在obj对象中的值
field.setAccessible(true);
String value = field.get(obj) + "";
ps.println(name + "=" + value);
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
Demo.java
/**
* 目标:提供一个通用框架,支持保存所有对象的具体信息
*/
public class Demo {
public static void main(String[] args) {
Student s = new Student("小明",'男',10,"三年二班","乒乓球");
MybatisUtil.save(s);
Teacher t = new Teacher("小红",'女',3000);
MybatisUtil.save(t);
}
}
- 反射的作用
- 可以在运行时得到一个类的全部成分然后操作
- 可以破坏封装性
- 可以破坏泛型的约束性
- 适合做Java高级框架