反射:
是针对Class对象进行操作的
是一种针对这个Class对象解剖的技术(构造器,成员方法,成员变量)
简单说,就是对运行时获取编译后的class文件,通过反射技术,动态的去获取构造,成员变量,成员方法反射技术实现要素及其核心思想: Class对象利用class对象去动态获取所需的构造,成员变量,成员方法
1.使用类名.class -> 详看使用场景3
类名.class; // 直接通过类名获取类的class对象
2.使用Class.forName(),好处:在运行程序的时候,动态加载类的class字节码到内存,然后生成对象 -> 详看使用场景1
Class.forName("类的全限定名[带有包名的类]"); // 如com.jdbc.mysql.Driver // 全限定名 = 顶部package后地址+类名
3.使用对象名.getClass() -> 详看使用场景2
对象名.getClass(); // 直接通过对象名来创建class对象,用于创建具体对象后
易错纠正:不存在 对象名.class(),正确写法为 对象.getClass()
场景1:读取配置文件,使用了获取类输入流来读取配置,再使用Class.forName()动态加载类先创建好一个配置文件student.ini在src目录下
className=com.mysql.jdbc.Driver
之后在Main类中
Properties prop = new Properties(); prop.load(Main.class.getClassLoader().getResourceAsStream("bean.properties"));//读配置 String className = prop.getProperty("className");//通过Key找value Class.forName(className); // 动态的加载Class对象
场景2:当方法中是形参传递的是对象需要获取class的时候
public void method(Student stu){ Class<Student> stucls = stu.getClass(); }
场景3:当明确类名的时候
类名.class;直接得到class对象
对于当前对象获取class,可以直接使用this.getClass()来替代类名.class
成员方法1.得到public构造器对象
class对象.getConstructor(); // 只能获取public无参构造 class对象.getConstructor(参数类型.class); // 获取public有参构造
成员方法2.得到任意权限构造器对象(包含私有)
class对象.getDeclaredConstructor();
成员方法3:调用构造创建对象
构造器对象.newInstance();
先创建javabean的对象Student
@Data // get、set、toString @AllArgsConstructor // 全参构造 @NoArgsConstructor // 无参构造 public class Student { private String name; private int age; }
// 得到class的对象 Class<? extends Student> aClass = new Student().getClass(); // 得到无参构造器 Constructor<? extends Student> constructor = aClass.getConstructor(); // 通过构造器创建对象 Student student = constructor.newInstance(); student.setName("zhangsan"); student.setAge(13); System.out.println(student.toString());
Class<? extends Student> aClass = new Student().getClass(); // 得到带参构造器,并指明构造的数据类型 Constructor<? extends Student> constructor = aClass.getConstructor(String.class,int.class); // 传入参数创建对象 Student student = constructor.newInstance("张三",12); System.out.println(student.toString());
// 获取私有构造器 Constructor<? extends Student> decConstructor = aClass.getDeclaredConstructor(); // 关闭权限校验,暴力访问 decConstructor.setAccessible(true); // 创建对象 Student student = decConstructor.newInstance();
getField("变量名"):仅获取public公开成员变量
getDeclaredField("变量名"):获取所有权限成员变量(private/protected/public)
field.setAccessible(true); // 暴力反射,解除私有权限限制 field.set(对象, 赋值); // 给对象的成员变量赋值 field.get(对象); // 获取对象的成员变量值
// 1.获取Class对象 Class<Student> studentClass = Student.class; // 2.获取私有成员变量name Field nameField = studentClass.getDeclaredField("name"); // 3.暴力解除权限 nameField.setAccessible(true); // 4.创建空对象 Student student = studentClass.newInstance(); // 5.给私有变量赋值 nameField.set(student, "李四"); // 6.获取变量值 String name = (String) nameField.get(student); System.out.println(name);
getMethod("方法名",参数类型.class):仅获取public公开方法
getDeclaredMethod("方法名",参数类型.class):获取所有权限方法(包含私有)
method.setAccessible(true); // 暴力反射(私有方法必须加) method.invoke(对象, 方法参数); // 执行方法,返回方法返回值
// 1.获取Class对象 Class<Student> studentClass = Student.class; Student student = studentClass.newInstance(); // 2.获取setName公开方法 Method setName = studentClass.getMethod("setName", String.class); // 3.执行set方法赋值 setName.invoke(student, "王五"); // 4.获取getName公开方法并执行 Method getName = studentClass.getMethod("getName"); String resName = (String) getName.invoke(student); System.out.println(resName);
// 获取私有方法 Method privateMethod = studentClass.getDeclaredMethod("私有方法名"); // 解除权限 privateMethod.setAccessible(true); // 执行私有方法 privateMethod.invoke(student);
getXXX():只能获取 public 权限的构造、变量、方法
getDeclaredXXX():可以获取 所有权限(private/默认/protected/public)
所有私有资源操作必须加:setAccessible(true),否则报错权限不足
反射全部API均抛出编译时异常,代码必须try-catch捕获
Class.forName() 常用于框架配置文件加载、解耦
反射最大特点:编译期不知道类型,运行期动态操作
获取构造器:getConstructor() / getDeclaredConstructor()
获取成员变量:getField() / getDeclaredField()
获取成员方法:getMethod() / getDeclaredMethod()
创建对象:newInstance()
newInstance():实例化对象
set():赋值
get():取值
setAccessible():暴力反射
invoke():执行方法
setAccessible():暴力反射