反射原理

首先有个Student.java文件,编译后得到Student.class文件,程序运行加载到内存中时,jvm会为每个类创建一个Class对象,Student为Class<Student>,Teacher类为Class<Teacher>,Class对象中包含了该类的成员变量,构造方法,成员方法等信息。
反射应用
开发工具,如idea,eclipse
各种框架,如spring,mybatis
Class对象的获取方式
类名.class
对象.getClass(从object继承过来的)
Class.forName(“全限定类名”)
Class对象的常用方法

package com.itheima;
/**
* 反射
*
* 任王胡
* 2023-03-05 13:09
*/
public class TestStudent {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException {
// 通过反射获得某个类的对象的三个方法
// 方法一:类名.class
Class<Student> studentClass = Student.class;
// 方法二:对象名.getClass----继承object类中的方法
Student student = new Student();
Class<? extends Student> studentClass1 = student.getClass();
// 方法三:Class.forName("全限定类型")
Class<?> studentClass2 = Class.forName("com.itheima.Student");
System.out.println(studentClass);
System.out.println(studentClass1);
System.out.println(studentClass2);
// Class对象的常用方法
System.out.println(studentClass.getSimpleName());
System.out.println(studentClass.getName());
Student student1 = studentClass.newInstance(); // 对象.newInstance就是在调用类的公有无参构造,如果该类没有公有无参构造方法,则报错
System.out.println(student1);
}
}
执行结果
class com.itheima.Student
class com.itheima.Student
Student
com.itheima.Student
com.itheima.Student@4554617c
Process finished with exit code 0
反射操作类的构造方法
目的:类中的每个构造方法都对应一个Constructor对象,先获取到Constructor对象,再用Constructor对象创建该类的对象
好处:创建对象不用new了,可以用反射,在程序运行期间获取某个类的对象,降低耦合度

package com.itheima;
/**
* 任王胡
* 2023-03-05 13:08
*/
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name) {
this.name = name;
}
private Student(int age) {
this.age = age;
}
private 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;
}
public void study(){
System.out.println("好好学习,天天向上");
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
学生类,公有无参,公有name,私有age,私有name和age
package com.itheima;
import java.lang.reflect.Constructor;
import java.lang.reflect.InvocationTargetException;
import java.util.Arrays;
/**
* 任王胡
* 2023-03-05 15:39
*/
public class TestStudent1 {
public static void main(String[] args) throws ClassNotFoundException, NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
Class<?> studentClass = Class.forName("com.itheima.Student");
Constructor<?> cons = studentClass.getConstructor(); // 获取公有无参
System.out.println(cons);
Constructor<?> cons1 = studentClass.getConstructor(String.class); // 获取公有的带name的构造方法
System.out.println(cons1);
System.out.println("--------------");
Constructor<?>[] consList = studentClass.getConstructors(); //获取所有公有
Arrays.stream(consList).forEach(System.out::println);
System.out.println("--------------");
Constructor<?> cons2 = studentClass.getDeclaredConstructor(); //获取公有无参
System.out.println(cons2);
Constructor<?> cons3 = studentClass.getDeclaredConstructor(String.class, int.class); // 获取私有name和age
System.out.println(cons3);
System.out.println("--------------");
Constructor<?>[] consList1 = studentClass.getDeclaredConstructors(); // 获取所有构造
Arrays.stream(consList1).forEach(System.out::println);
System.out.println("--------------");
// 创建对象
/*
* cons 公有无参
* cons1 公有name
* cons2 公有无参
* cons3 私有name和age
*
* */
Object object = cons.newInstance();
System.out.println(object);
Object object1 = cons1.newInstance("jack");
System.out.println(object1);
// Object object2 = cons3.newInstance("tom", 18);
//如果像上一行那样直接设置值,会报错,因为私有构造不能直接访问,需要设置暴力访问
cons3.setAccessible(true); // 设置允许暴力访问
Object object3 = cons3.newInstance("jack", 20);
System.out.println(object3);
}
}
执行结果
public com.itheima.Student()
public com.itheima.Student(java.lang.String)
--------------
public com.itheima.Student(java.lang.String)
public com.itheima.Student()
--------------
public com.itheima.Student()
private com.itheima.Student(java.lang.String,int)
--------------
private com.itheima.Student(java.lang.String,int)
private com.itheima.Student(int)
public com.itheima.Student(java.lang.String)
public com.itheima.Student()
--------------
Student{name='null', age=0}
Student{name='jack', age=0}
Student{name='jack', age=20}
Process finished with exit code 0
反射操作类的成员方法
目的:类中的每个成员方法都对应一个Method对象,先获取Method对象,再操作Method对象执行成员方法
作用:可以进行泛型擦除

invoke方法参数:第一个,该类的实例对象,第二个,成员方法的参数
操作成员方法和操作构造方法一样,只是方法名不同而已
演示:泛型擦除(泛型只针对编译期间,运行期间无效)
package com.itheima;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.List;
/**
* 泛型擦除
*
* 任王胡
* 2023-03-05 16:47
*/
public class Demo1 {
public static void main(String[] args) throws NoSuchMethodException, InvocationTargetException, IllegalAccessException {
List<String> list=new ArrayList<>();
list.add("it");
list.add("java");
// list.add(666); // 编译报错
System.out.println(list);
// 1.获取ArrayList类的字节码对象
Class<? extends List> clazz = list.getClass();
// 2.获取ArrayList的实例对象(不需要,已经有了list)
// 3.获取成员方法对应的Method对象
Method add = clazz.getMethod("add", Object.class);
add.invoke(list,666);
System.out.println(list);
}
}
执行结果
[it, java]
[it, java, 666]
Process finished with exit code 0
反射操作类的成员变量
类似构造方法和成员方法
对应的类:Field
对应的方法:
getField
getFields
getDeclaredField
getDeclaredFields
目的:给成员变量设置值,获取对象的成员变量
package com.itheima;
/**
* 任王胡
* 2023-03-05 13:08
*/
public class Student {
private String name;
private int age;
public Student() {
}
public Student(String name) {
this.name = name;
}
private Student(int age) {
this.age = age;
}
private 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;
}
public void study(){
System.out.println("好好学习,天天向上");
}
@Override
public String toString() {
return "Student{" +
"name='" + name + '\'' +
", age=" + age +
'}';
}
}
package com.itheima;
import java.lang.reflect.Field;
/**
* 任王胡
* 2023-03-05 17:36
*/
public class TestStudent2 {
public static void main(String[] args) throws ClassNotFoundException, IllegalAccessException, InstantiationException, NoSuchFieldException {
// 获取字节码对象
Class<?> clazz = Class.forName("com.itheima.Student");
// 获取Student类的对象
Object student = clazz.newInstance();
// 获取成员变量对应的Field类对象
Field name = clazz.getDeclaredField("name");
// 暴力反射
name.setAccessible(true);
// 给实例对象设置值
name.set(student,"rose");
Field age = clazz.getDeclaredField("age");
age.setAccessible(true);
age.set(student,18);
System.out.println(student);
// 获取某个对象的成员变量的值
Object o = name.get(student);
System.out.println(o);
}
}
执行结果
Student{name='rose', age=18}
Process finished with exit code 0
总结
使用反射的步骤
获取某个类的Class对象
通过Class对象获取某个类的实例对象
通过Class对象获取类的成员方法Method对象
调用Method对象的invoke方法,执行成员方法