P02 反射
- 1.反射概述
- 1.1 反射的基本作用
- 1.2 反射的关键
- 2.反射获取类对象
- 2.1 forName(String className)
- 2.2 类名.class
- 2.3 对象.getClass()
- 3.反射获取构造器对象![在这里插入图片描述](https://img-blog.csdnimg.cn/e234dd155af94a5c80223d64b112f4bf.png)
- 3.1 Class 类中用于获取构造器的方法
- 3.2 Constructor 类中常用方法
- 3.3 测试案例
- 4.反射获取成员变量对象
- 4.1 Class 类中用于获取成员变量的方法
- 4.2 Field 类中常用方法
- 4.3 测试案例
- 5.反射获取方法对象
- 5.1 Class 类中用于获取成员方法的方法
- 5.2 Method 类中常用方法
- 5.3 测试案例
- 6.反射的作用
- 6.1 绕过编译阶段为集合添加数据
- 6.2 通过框架的底层原理
- 6.2.1 需求分析
- 6.2.2 代码实例
- 6.2.3 运行结果
系统:Win10
Java:1.8.0_333
IDEA:2020.3.4
Gitee:https://gitee.com/lijinjiang01/JavaWeb
1.反射概述
1.1 反射的基本作用
反射:反射是指对于任何一个 Class 类,在“运行的时候”都可以直接得到这个类全部成分
在运行时,可以直接得到这个类的构造器对象:Constructor
在运行时,可以直接得到这个类的成员变量对象:Field
在运行时,可以直接得到这个类的成员方法对象:Method
这种运行时动态获取类信息以及动态调用类中成分的能力称为 Java 语言的反射机制
1.2 反射的关键
反射第一步都是先得到编译后的 Class 类对象,然后就可以得到 Class 的全部成分
反射的核心思想和关键就是:得到编译以后的 class 文件对象
2.反射获取类对象
获取 Class 类对象的三种方式:
2.1 forName(String className)
Class 类中的一个静态方法:forName(String className)
Class c1 = Class.forName("com.lijinjiang.reflect01_class.Student");
2.2 类名.class
Class c2 = Student.class;
2.3 对象.getClass()
利用 Object 对象的 getClass() 方法获取对象对应类的 Class 对象
Student stu = new Student();
Class c3 = stu.getClass();
3.反射获取构造器对象
3.1 Class 类中用于获取构造器的方法
方法 | 说明 |
---|---|
Constructor[] getConstructors() | 返回所有公共构造器对象的数组 |
Constructor[] getDeclaredConstructors() | 返回所有构造器对象的数组,存在就能拿到 |
Constructor getConstructor(Class… parameterTypes) | 返回指定的公共构造器对象 |
Constructor getDeclaredConstructor(Class… parameterTypes) | 返回指定的构造器对象,存在就能拿到 |
3.2 Constructor 类中常用方法
方法 | 说明 |
---|---|
T newInstance(Object… initargs) | 根据执行的构造器创建对象 |
void setAccessible(boolean flag) | 设置为true,表示取消访问检查,进行暴力反射 |
3.3 测试案例
首先创建 Student 类对象
public class Student {private String name;private int age;private Student() {System.out.println("无参构造器执行");}private Student(String name){this.name = name;System.out.println("有参构造器执行");}public Student(String name, int age) {this.name = name;this.age = age;System.out.println("全参构造器执行");}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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
测试获取构造器方法
import org.junit.Test;
import java.lang.reflect.Constructor;public class TestConstructor01 {// 1.getConstructors@Testpublic void testGetConstructors() {// 1.获取类对象Class c = Student.class;// 2.获取所有类对象的公共构造器Constructor[] constructors = c.getConstructors();// 3.遍历for (Constructor constructor : constructors) {System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());}}// 2.getDeclaredConstructors@Testpublic void testGetDeclaredConstructors() {// 1.获取类对象Class c = Student.class;// 2.获取所有类对象的构造器Constructor[] constructors = c.getDeclaredConstructors();// 3.遍历for (Constructor constructor : constructors) {System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());}}// 3.getConstructor(Class<?>... parameterTypes)@Testpublic void testGetConstructor() throws Exception {// 1.获取类对象Class c = Student.class;// 2.获取所有类对象的构造器Constructor constructor = c.getConstructor(String.class, int.class);// 3.输出System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());}// 4.getDeclaredConstructor(Class<?>... parameterTypes)@Testpublic void testGetDeclaredConstructor() throws Exception {// 1.获取类对象Class c = Student.class;// 2.获取所有类对象的构造器Constructor constructor = c.getDeclaredConstructor();// 3.输出System.out.println(constructor.getName() + "===>" + constructor.getParameterCount());}
}
测试使用构器创建对象方法
import org.junit.Test;
import java.lang.reflect.Constructor;public class TestConstructor02 {// 1.T newInstance(Object... initargs)@Testpublic void testNewInstance() throws Exception {// 1.获取类对象Class c = Student.class;// 2.获取Student(String name)构造器,并以此创建对象Constructor c01 = c.getDeclaredConstructor(String.class);c01.setAccessible(true); // 暴力反射Student stu01 = (Student) c01.newInstance("张三");System.out.println(stu01);// 3.获取Student(String name, int age)构造器,并以此创建对象Constructor c02 = c.getDeclaredConstructor(String.class,int.class);Student stu02 = (Student) c02.newInstance("李四",27);System.out.println(stu02);}
}
4.反射获取成员变量对象
4.1 Class 类中用于获取成员变量的方法
方法 | 说明 |
---|---|
Field[] getFields() | 返回所有公共成员变量对象的数组 |
Field[] getDeclaredFields() | 返回所有成员变量对象的数组,存在就能拿到 |
Field getField(String name) | 返回指定公共成员变量对象 |
Field getDeclaredField(String name) | 返回指定成员变量对象,存在就能拿到 |
4.2 Field 类中常用方法
方法 | 说明 |
---|---|
void set(Object obj, Object value) | 给指定对象的此成员变量设置指定的新值 |
Object get(Object obj) | 获取指定对象的该成员变量的值 |
void setAccessible(boolean flag) | 暴力反射,设置为true可以直接访问私有属性的变量 |
Class getType() | 获取变量的类型,返回类型Class对象 |
String getName() | 获取变量的名称 |
4.3 测试案例
首先创建 Student 类对象
public class Student {private String name;private int age;public static String school;public static final String COUNTRY = "中国";public Student() {}private Student(String name) {this.name = name;}public Student(String name, int age) {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;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +'}';}
}
测试获取成员变量的方法
import org.junit.Test;
import java.lang.reflect.Field;public class TestField01 {// 1.getFields()// 2.getDeclaredFields()@Testpublic void testGetDeclaredFields() {// 1.获取 class 对象Class c = Student.class;// 2.获取公共成员变量数组Field[] fields = c.getDeclaredFields();// 3.遍历for (Field field : fields) {System.out.println(field.getName() + "===>" + field.getType());}}// 3.getField(String name)// 4.getDeclaredField(String name)@Testpublic void testGetDeclaredField() throws Exception {// 1.获取 class 对象Class c = Student.class;// 2.获取公共成员变量数组Field field = c.getDeclaredField("age");// 3.输出System.out.println(field.getName() + "===>" + field.getType());}
}
测试成员变量的赋值和取值方法
import org.junit.Test;
import java.lang.reflect.Field;public class TestField02 {@Testpublic void testSetField() throws Exception {// 1.获取class对象Class c = Student.class;// 2.获取指定成员变量Field field = c.getDeclaredField("age");field.setAccessible(true);// 3.赋值Student stu01 = new Student();field.set(stu01, 18);System.out.println(stu01);// 4.取值Student stu02 = new Student("李四", 27);int age = (int) field.get(stu02);System.out.println(age);}
}
5.反射获取方法对象
5.1 Class 类中用于获取成员方法的方法
方法 | 说明 |
---|---|
Method[] getMethods() | 返回所有公共成员方法对象的数组 |
Method[] getDeclaredMethods() | 返回所有成员方法对象的数组,存在就能拿到 |
Method getMethod(String name, Class… parameterTypes) | 返回指定公共成员方法对象 |
Method getDeclaredMethod(String name, Class… parameterTypes) | 返回指定成员方法对象,存在就能拿到 |
5.2 Method 类中常用方法
方法 | 说明 |
---|---|
Object invoke(Object obj, Object… args) | 运行方法 参数一:用obj对象调用该方法 参数二:调用方法传递的参数(如果没有就不写) 返回值:方法的返回值(如果没有就不写) |
void setAccessible(boolean flag) | 暴力反射,设置为true可以直接调用私有方法运行 |
5.3 测试案例
首先创建 Dog 类对象
public class Dog {private String name;public Dog() {}public Dog(String name) {this.name = name;}public void run() {System.out.println("小狗跑的飞快");}private void eat() {System.out.println("狗吃骨头");}private String eat(String name) {System.out.println("狗在吃" + name);return "吃的很开心";}public static void inAddr() {System.out.println("在上海有一只单身狗");}public String getName() {return name;}public void setName(String name) {this.name = name;}
}
测试获取成员方法的方法以及测试方法运行的方法
import org.junit.Test;
import java.lang.reflect.Method;public class TestMethod01 {// 1.getMethods()// 2.getDeclaredMethods()@Testpublic void testGetDeclaredMethods() {// 1.获取 class 对象Class c = Dog.class;// 2.获取成员方法数组Method[] methods = c.getDeclaredMethods();// 3.遍历for (Method method : methods) {System.out.println(method.getName() + " 返回值类型" + method.getReturnType() + " 参数个数" + method.getParameterCount());}}// 3.getMethod(String name, Class<?>... parameterTypes)// 4.getDeclaredMethod(String name, Class<?>... parameterTypes)@Testpublic void testGetDeclaredMethod() throws Exception {// 1.获取 class 对象Class c = Dog.class;// 2.获取成员方法数组Method method01 = c.getDeclaredMethod("eat");method01.setAccessible(true);Method method02 = c.getDeclaredMethod("eat",String.class);method02.setAccessible(true);// 3.执行方法Dog dog = new Dog();Object res01 = method01.invoke(dog);Object res02 = method02.invoke(dog, "稀饭");System.out.println(res01);System.out.println(res02);}
}
6.反射的作用
6.1 绕过编译阶段为集合添加数据
反射是作用在运行时的技术,此时集合的泛型将不能再产生约束了,此时是可以为集合存入其他任意类型的元素的
泛型只是在编译阶段可以约束集合只能操作某种数据类型,在编译成 Class 文件进入运行阶段的时候,其真实类型都是 ArrayList 了,泛型相当于被擦除了
代码如下:
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;public class ReflectDemo {public static void main(String[] args) throws Exception {List<String> list01 = new ArrayList<>();List<Integer> list02 = new ArrayList<>();System.out.println(list01.getClass());System.out.println(list02.getClass());System.out.println(list01.getClass() == list02.getClass()); // ArrayList.classSystem.out.println("==============================");List<Integer> list03 = new ArrayList<>();list03.add(100);list03.add(200);// list03.add("三百");// 1.获取class对象Class c = list03.getClass();// 2.获取指定methodMethod method = c.getMethod("add",Object.class);// 3.运行该方法boolean b = (boolean) method.invoke(list03, "三百");System.out.println(b);System.out.println(list03);System.out.println("==============================");List list04 = list03;list04.add("四百");list04.add(true);System.out.println(list03);}
}
6.2 通过框架的底层原理
6.2.1 需求分析
需求:给任意一个对象,在不清楚对象字段的情况下,可以把对象的字段名称和对应值存储到文件中去
分析:
- 定义一个方法,可以接收任意类的对象
- 使用反射获取对象的 Class 类对象,然后获取全部成员变量信息
- 遍历成员变量信息,然后提取本成员变量在对象中的具体值
- 存入成员变量名称和值到文件中去即可
6.2.2 代码实例
创建 Student、Teacher 类
public class Student {private String name;private char sex;private int age;private String classroom;private String hobby;public Student() {}public Student(String name, char sex, int age, String classroom, String hobby) {this.name = name;this.sex = sex;this.age = age;this.classroom = classroom;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 getClassroom() {return classroom;}public void setClassroom(String classroom) {this.classroom = classroom;}public String getHobby() {return hobby;}public void setHobby(String hobby) {this.hobby = hobby;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", sex=" + sex +", age=" + age +", classroom='" + classroom + '\'' +", hobby='" + hobby + '\'' +'}';}
}
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;}@Overridepublic String toString() {return "Teacher{" +"name='" + name + '\'' +", sex=" + sex +", salary=" + salary +'}';}
}
创建工具类
import java.io.FileOutputStream;
import java.io.PrintStream;
import java.lang.reflect.Field;
import java.lang.reflect.Method;public class MybatisUtil {/*** 保存任意类型的对象*/public static void save(Object obj) {try {PrintStream ps = new PrintStream(new FileOutputStream("P02_Reflect/src/com/lijinjiang/reflect06_framework/data.txt", true));// 1.获取class对象Class c = obj.getClass(); // c.getSimpleName() 获取当前类名 c.getName() 获取全限名:包名+类名String simpleName = c.getSimpleName();ps.println("===============" + simpleName + "===============");// 2.获取全部成员变量Field[] fields = c.getDeclaredFields();// 3.获取成员变量的值for (Field field : fields) {field.setAccessible(true);String name = field.getName();String value = field.get(obj) + "";ps.println(name + "=" + value);}ps.close();} catch (Exception e) {e.printStackTrace();}}
}
创建测试类
public class ReflectDemo {public static void main(String[] args) {Teacher teacher01 = new Teacher("古越涛", '男', 3999.9);Teacher teacher02 = new Teacher("裴佩", '女', 4999.0);Student student = new Student("蓝菲琳", '女', 18, "三年八班", "唱歌、跳舞");MybatisUtil.save(teacher01);MybatisUtil.save(teacher02);MybatisUtil.save(student);}
}