反射
反射就是拿到类文件, 然后操作类的成分(成员变量, 方法, 构造器等)

反射具体学什么?
通过加载类文件, 获取类的成分信息, 操作他们
- 反射第一步: 加载类,获取类的字节码 (Class对象)
- 获取类的构造器: Constructor对象
- 获取类的成员变量: Field对象
- 获取类的成员方法: Method对象
反射第一步: 加载类,获取类的字节码 (Class对象)

public class GetClass {
public static void main(String[] args) throws ClassNotFoundException {
// 目标: 获取类的Class对象 (类文件)
// 1.通过类名获取类: 类.class
Class c1 = Student.class;
System.out.println(c1); // class com.itheima.Student
// 2.通过Class提供的方法获取类: Class.forName("类的全名称")
Class c2 = Class.forName("com.itheima.Student");
System.out.println(c2); // class com.itheima.Student
// 3.通过Object提供的方法获取类: 对象.getClass()
Student s = new Student();
Class c3 = s.getClass();
System.out.println(c3); // class com.itheima.Student
// 类文件在系统中只有一份, 三种方式拿到的类文件都是同一个class对象
System.out.println(c1 == c2); // true
System.out.println(c2 == c3); // true
}
}
获取类的构造器: Constructor对象
Class提供了从类中获取构造器的方法

使用获取到的构造器: 初始化对象返回

public class GetClassInfo {
public static void main(String[] args) throws Exception {
// 目标: 通过反射获取类的所有信息
// 1.获取类文件的信息
getClassInfo();
// 2.获取类的构造器
}
// 2.获取类的构造器
private static void getConstructors() throws Exception {
Class c1 = Student.class;
// 2.1获取类的全部构造器
Constructor[] sons = c1.getDeclaredConstructors();
for (Constructor son : sons) {
System.out.println(son.getName() + "(" + son.getParameterCount() + "个参数)");
}
// 2.2获取单个构造器
Constructor son = c1.getDeclaredConstructor(); // 获取无参构造器
System.out.println(son.getName() + "(" + son.getParameterCount() + "个参数)");
Constructor son2 = c1.getDeclaredConstructor(String.class, int.class); // 获取有参构造器
System.out.println(son2.getName() + "(" + son2.getParameterCount() + "个参数)");
// 2.3获取构造的作用就是创建对象
Student s1 = (Student) son.newInstance();
System.out.println(s1);
// 2.4暴力反射 可以访问私有的构造器,成员变量和方法
son2.setAccessible(true);
Student s2 = (Student) son2.newInstance("张三", 19);
System.out.println(s2);
}
// 1.获取类文件的信息
private static void getClassInfo() {
Class c1 = Student.class;
System.out.println(c1.getName()); // 获取类的全类名 com.itheima.Student
System.out.println(c1.getSimpleName()); // 获取类的简类名 Student
}
}
获取类的成员变量: Field对象
Class提供了从类中获取成员变量的方法

为成员变量取值/赋值

public class GetClassInfo {
public static void main(String[] args) throws Exception {
// 目标: 通过反射获取类的所有信息
// 3.获取类的成员变量
getFields();
// 4.获取类的成员方法
getMethods();
}
// 3.获取类的成员变量
private static void getFields() throws Exception {
Class c1 = Student.class;
// 3.1获取类的全部成员变量
Field[] fields = c1.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName() + "(" + field.getType().getName() + ")");
}
// 3.2获取单个成员变量
Field name = c1.getDeclaredField("name"); // 获取name成员变量
System.out.println(name.getName() + "(" + name.getType().getName() + ")");
Field age = c1.getDeclaredField("age");
System.out.println(age.getName() + "(" + age.getType().getName() + ")");
// 3.3获取成员变量的作用就是取值赋值
Student student = new Student(); // 得到学生对象
name.setAccessible(true); // 暴力反射: 绕过访问权限修饰符
name.set(student, "李四"); // 变量赋值
age.set(student, 18); // 变量赋值
String sname = (String) name.get(student); // 变量取值
int sage = (int) age.get(student); // 变量取值
}
}
获取类的成员方法: Method对象
Class提供了从类中获取成员方法的API

执行获取到的方法

package com.itheima;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class GetClassInfo {
public static void main(String[] args) throws Exception {
// 目标: 通过反射获取类的所有信息
// 4.获取类的成员方法
getMethods();
}
// 4.获取类的成员方法
private static void getMethods() throws Exception {
Class c1 = Student.class;
// 4.1获取类的全部成员方法
Method[] methods = c1.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName() + "(" + method.getParameterCount() + "个参数)");
}
// 4.2获取单个成员方法
Method method = c1.getDeclaredMethod("setName", String.class); // 获取setName方法
System.out.println(method.getName() + "(" + method.getParameterCount() + "个参数)");
// 4.3获取成员方法的目的就是执行该方法
Student student = new Student();
method.setAccessible(true); // 暴力反射: 绕过访问权限修饰符
method.invoke(student, "张三"); // 执行setName方法
}
}
反射的作用
-
可以得到一个类的全部成分然后操作。
-
可以破坏封装性。
-
可以绕过泛型的约束
-
主流的框架都会基于反射设计出一些通用的功能。
public class Demo {
public static void main(String[] args) throws Exception {
// 目标: 了解反射的作用
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("令狐冲");
list.add("东方不败");// 通过反射绕过泛型的约束 Class c1 = list.getClass(); Method add = c1.getDeclaredMethod("add",Object.class); add.invoke(list,98); add.invoke(list,true); System.out.println(list); // [张无忌, 令狐冲, 东方不败, 98, true] }
}
案例
需求: 对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去

-
定义一个方法, 接收任意对象
-
通过反射获取对象的Class对象, 然后获取全部的成员变量
-
遍历成员变量, 然后提取成本成员变量的值
-
把成员变量名, 变量值, 写入到文件中
public class Demo {
public static void main(String[] args) throws Exception {
// 反射是框架的核心技术
Dog dog = new Dog("哈士奇", 4);
Student student = new Student("小明", 19, 100);SaveObjectFrameWork.saveObject(dog); // 保存dog对象到文件中 SaveObjectFrameWork.saveObject(student); // 保存student对象到文件中 }
}
public class SaveObjectFrameWork {
// 保存任意对象的静态方法
public static void saveObject(Object obj) throws Exception {
// 打印流
PrintStream ps = new PrintStream(new FileOutputStream("day8-reflect\src\com\itheima\test3\obj.txt", true));// 获取类文件 Class c = obj.getClass(); String simpleName = c.getSimpleName(); ps.println("==========" + simpleName + "=========="); // 获取所有的成员变量 Field[] fields = c.getDeclaredFields(); for (Field field : fields) { String fieldName = field.getName(); // 获取变量名 field.setAccessible(true); // 暴力反射, 绕过权限修饰符 Object fileValue = field.get(obj); // 获取变量值 ps.println(fieldName + "=" + fileValue); } ps.close(); }
}
