一、认识反射
1.1、认识
反射就是:加载类,并允许以编程的方式解剖类中的各种成分(成员变量、方法、构造器等)。


1.2、学习获取类的信息、操作它们(步骤)
1 、反射第一步:加载类,获取类的字节码: Class 对象
2 、获取类的构造器: Constructor对象
3 、获取类的成员变量: Field对象
4 、获取类的成员方法: Method对象
全部认识完后,再看反射的应用场景
二、获取类(获取Class对象的三种方式)
Class cl=类名.class
调用Class提供方法:public static Class forName(String package);
Object提供的方法:public ClassgetClass();Class c3=对象.getClass();
public class ReflectDemo1 {
public static void main(String[] args) throws Exception {
// 目标:掌握反射第一步操作:或者类的Class对象。(获取类本身)。
// 1、获取类本身:类.class
Class c1 = Student.class;
System.out.println(c1);
// 2、获取类本身:Class.forName("类的全类名")
Class c2 = Class.forName("com.heima.reflect.Student");
System.out.println(c2);
// 3、获取类本身:对象.getClass()
Student s = new Student();
Class c3 = s.getClass();
System.out.println(c3);
System.out.println(c1 == c2); // true
System.out.println(c2 == c3); // true
}
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private String name;
private int age;
private String hobby;
}
三、获取类中的成分、并对其进行操作
3.1、构造器
Class 提供了从类中获取构造器的方法

获取类构造器的作用:依然是初始化对象返回

3.2、成员变量
Class 提供了从类中获取成员变量的方法

获取到成员变量的作用:依然是赋值、取值

3.3、成员方法
Class 提供了从类中获取成员方法的 API

成员方法的作用:依然是执行

3.4、示例
import org.junit.Test;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectDemo2 {
@Test
public void getClassInfo(){
// 目标:获取类的信息。
// 1、反射第一步:或者Class对象,代表拿到类。
Class c1 = Student.class;
System.out.println(c1.getName()); // 类名的全类名 com.itheima.demo2reflect.Student
System.out.println(c1.getSimpleName()); // 类名 Student
}
// 2、获取类的构造器对象并对其进行操作。
@Test
public void getConstructorInfo() throws Exception {
// 目标:获取类的构造器对象并对其进行操作。
// 1、反射第一步:或者Class对象,代表拿到类。
Class c1 = Dog.class;
// 2、获取构造器对象。
Constructor[] cons = c1.getDeclaredConstructors();
for (Constructor con : cons) {
System.out.println(con.getName() + "(" + con.getParameterCount() + ")");
}
// 3、获取单个构造器
Constructor con = c1.getDeclaredConstructor(); // 无参数构造器
System.out.println(con.getName() + "(" + con.getParameterCount() + ")");
Constructor con2 = c1.getDeclaredConstructor(String.class, int.class); // 2个参数的有参数构造器
System.out.println(con2.getName() + "(" + con2.getParameterCount() + ")");
// 4、获取构造器的作用依然是创建对象:创建对象。
// 暴力反射:暴力反射可以访问私有的构造器、方法、属性。
con.setAccessible(true); // 绕过访问权限,直接访问!
Dog d1 = (Dog) con.newInstance();
System.out.println(d1);
Dog d2 = (Dog)con2.newInstance("小黑", 3);
System.out.println(d2);
}
// 3、获取类的成员变量对象并对其进行操作。
@Test
public void getFieldInfo() throws Exception {
// 目标:获取类的成员变量对象并对其进行操作。
// 1、反射第一步:或者Class对象,代表拿到类。
Class c1 = Dog.class;
// 2、获取成员变量对象。
Field[] fields = c1.getDeclaredFields();
for (Field field : fields) {
System.out.println(field.getName() + "(" + field.getType().getName() + ")");
}
// 3、获取单个成员变量对象。
Field field = c1.getDeclaredField("hobby");
System.out.println(field.getName() + "(" + field.getType().getName() + ")");
Field field2 = c1.getDeclaredField("age");
System.out.println(field2.getName() + "(" + field2.getType().getName() + ")");
// 4、获取成员变量的目的依然是取值和赋值。
Dog d = new Dog("泰迪", 3);
field.setAccessible(true); // 绕过访问权限,直接访问!
field.set(d, "社交"); // d.setHobby("社交");
System.out.println(d);
String hobby = (String) field.get(d); // d.getHobby();
System.out.println(hobby);
}
// 4、获取类的成员方法对象并对其进行操作。
@Test
public void getMethodInfo() throws Exception {
// 目标:获取类的成员方法对象并对其进行操作。
// 1、反射第一步:或者Class对象,代表拿到类。
Class c1 = Dog.class;
// 2、获取成员方法对象。
Method[] methods = c1.getDeclaredMethods();
for (Method method : methods) {
System.out.println(method.getName() + "(" + method.getParameterCount() + ")");
}
// 3、获取单个成员方法对象。
Method m1 = c1.getDeclaredMethod("eat");// 获取是无参数的eat方法
Method m2 = c1.getDeclaredMethod("eat", String.class);// 获取是有参数的eat方法
System.out.println(m1.getName() + "(" + m1.getParameterCount() + ")");
System.out.println(m2.getName() + "(" + m2.getParameterCount() + ")");
// 4、获取成员方法的目的依然是调用方法。
Dog d = new Dog("泰迪", 3);
m1.setAccessible(true); // 绕过访问权限,直接访问!
Object rs1 = m1.invoke(d); // 唤醒对象d的eat方法执行,相当于 d.eat();
System.out.println(rs1); // null
Object rs2 = m2.invoke(d, "牛肉"); // 唤醒对象d的eat带String参数的方法执行,相当于 d.eat("牛肉");
System.out.println(rs2);
}
}
public class Dog {
private String name;
private int age;
private String hobby;
private Dog() {
System.out.println("无参数构造器执行了~~");
}
private Dog(String name) {
System.out.println("1个参数有参数构造器执行了~~");
this.name = name;
}
public Dog(String name, int age) {
System.out.println("2个参数有参数构造器执行了~~");
this.name = name;
this.age = age;
}
private void eat(){
System.out.println("狗吃骨头!");
}
public String eat(String name){
System.out.println("狗吃" + name);
return "狗说:谢谢!谢谢!汪汪汪!";
}
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;
}
public String getHobby() {
return hobby;
}
public void setHobby(String hobby) {
this.hobby = hobby;
}
@Override
public String toString() {
return "Dog{" +
"name='" + name + '\'' +
", age=" + age +
", hobby='" + hobby + '\'' +
'}';
}
}
四、作用、应用场景
4.1、作用和用途
1、基本作用:可以得到一个类的全部成分然后操作。

2、可以破坏封装性。
3、可以绕过泛型的约束
4、最重要的用途是:适合做 Java 的框架,基本上,主流的框架都会基于反射设计出一些通用的功能。
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
public class ReflectDemo3 {
public static void main(String[] args) throws Exception {
// 目标:反射的基本作用。
// 1、类的全部成分的获取
// 2、可以破坏封装性
// 3、可以绕过泛型的约束。
ArrayList<String> list = new ArrayList<>();
list.add("张无忌");
list.add("令狐冲");
list.add("东方不败");
// list.add(9.9);
// list.add(true);
Class c1 = list.getClass(); // c1 == ArrayList.class
// 获取 ArrayList 类的add方法
Method add = c1.getDeclaredMethod("add", Object.class);
// 触发list集合对象的add方法执行。
add.invoke(list, 9.9); // 翻墙
add.invoke(list, true); // 翻墙
System.out.println(list);
}
}
4.2、应用场景-示例
4.2.1、使用反射做一个简易版的框架
需求:对于任意一个对象,该框架都可以把对象的字段名和对应的值,保存到文件中去。

4.2.2、实现步骤
1、定义一个方法,可以接收任意对象。
2、每收到一个对象后,使用反射获取该对象的Class对象,然后获取全部的成员变量。
3、遍历成员变量,然后提取成员变量在该对象中的具体值。
4、把成员变量名、和其值,写出到文件中去即可。
4.2.3、代码
public class ReflectDemo4 {
public static void main(String[] args) throws Exception {
// 目标:搞清楚反射的应用:做框架的通用技术。
Dog d = new Dog("小黑", 3);
SaveObjectFrameWork.saveObject(d);
// 创建学生对象
Student s = new Student("小明", 18, "爱问问题");
SaveObjectFrameWork.saveObject(s);
// 创建老师对象
Teacher t = new Teacher("小红", 19, "java、前端、动漫", 3000, "422期", '女', "12345678901");
SaveObjectFrameWork.saveObject(t);
}
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
private String name;
private int age;
private String hobby;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
private String name;
private int age;
private String hobby;
private double salary;
private String className;
private char sex;
private String phone;
}
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
public class SaveObjectFrameWork {
// 保存任意对象的静态方法
public static void saveObject(Object obj) throws Exception {
PrintStream ps = new PrintStream(new FileOutputStream("src/com/heima/reflect/obj.txt", true));
// obj 可能是学生 老师 狗
// 只有反射可以直到对象有多少个字段:
// 1. 获取Class对象
Class c = obj.getClass();
String simpleName = c.getSimpleName();
ps.println("==============" + simpleName + "====================");
// 2. 获取Class对象的所有字段。
Field[] fields = c.getDeclaredFields();
// 3. 遍历字段
for (Field field : fields) {
// 4. 获取字段的值
// 4.1 获取字段名称
String fieldName = field.getName();
// 4.2 获取字段的值
field.setAccessible(true); // 暴力反射
Object fieldValue = field.get(obj) + "";
// 5. 打印到文件中去
ps.println(fieldName + "=" + fieldValue);
}
ps.close();
}
}
1292

被折叠的 条评论
为什么被折叠?



