什么是反射?
- 反射是一种动态机制,让我们可以在程序运行时动态创建对象,获取到类的信息等,可以提高程序的灵活度,反射在框架中被大量运用
如何使用反射?
想要使用反射必须先获得一个类的字节码对象,也叫类对象(Class
对象),JVM在加载类时,会把.class
文件读取至内存, 生成一个Class
对象,由于双亲委派机制的存在,一个类的Class
对象在内存中只有一个
- 首先准备一个
Student
类
package reflect;
public class Student {
public Integer age;
private String name;
public Student(){
System.out.println("无参构造方法正在执行..");
}
public Student(String name,Integer age) {
this.name = name;
this.age = age;
}
public void sayHello(){
System.out.println("Student.sayHello()正在执行..");
}
public void sayHello(String name){
System.out.println("Student.sayHello()正在执行..传入的参数是: " + name);
}
private void privateMethod(){
System.out.println("Student.privateMethod()私有方法正在执行..");
}
}
- 获取类的
Class
对象
package reflect;
public class ReflectDemo1 {
public static void main(String[] args) {
// 第一种获取Class对象的方式
Student student = new Student(); // 实例化Student
Class stuClass1 = student.getClass();// 获取Class对象
System.out.println(stuClass1.getName());// 打印Class对象的全限定名
// 第二种获取Class对象的方式
Class stuClass2 = Student.class; // 获取Class对象
System.out.println(stuClass1 == stuClass2); // 比较两个是否是一个对象true
// 第三种获取Class对象的方式
try {
Class stuClass3 = Class.forName("reflect.Student");// 填入类的全限定名,需要捕获或抛出异常
System.out.println(stuClass2 == stuClass3);// 比较两个是否是一个对象true
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
- 调用构造方法来实例化对象
package reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
public class ReflectDemo2 {
public static void main(String[] args) {
try {
// 动态调用Student的无参构造方法
Class stuClass = Class.forName("reflect.Student");// 获取Class对象
stuClass.newInstance(); // 实例化对象
// 动态调用Student的有参构造方法
Constructor constructor = stuClass.getConstructor(String.class,Integer.class); // 指定构造器的参数数据类型
Object obj = constructor.newInstance("张三",18); // 传入参数
// 动态获取Student的公开属性
Field field = stuClass.getField("age");
Integer age =(Integer) field.get(obj); // 获取属性
System.out.println("学生的年龄为: " + age);
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 获取类的信息,属性,方法等等
package reflect;
import java.lang.reflect.Method;
public class ReflectDemo3 {
public static void main(String[] args) {
try {
// 动态调用类的无参方法
Class stuClass = Class.forName("reflect.Student");// 获取Class对象
Object obj = stuClass.newInstance(); // 实例化Student对象
Method sayHello = stuClass.getMethod("sayHello");// 获取需要调用的方法
sayHello.invoke(obj); // 执行方法
// 动态调用类的有参方法
Method setName = stuClass.getMethod("sayHello",String.class);// 需要传入发方法名和方法形参对应的数据类型
setName.invoke(obj, "你好");// 传入参数值并执行
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 反射可以强制访问类的私有属性和方法
package reflect;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
public class ReflectDemo4 {
public static void main(String[] args) {
try {
// 动态调用类的私有属性
Class stuClass = Class.forName("reflect.Student");
Constructor constructor = stuClass.getConstructor(String.class, Integer.class);
Object obj = constructor.newInstance("张三",18);
Field field = stuClass.getDeclaredField("name"); // 可以获取类中的所有属性,包括私有属性
field.setAccessible(true); // 暴力反射,强制开启该属性的访问权限
System.out.println(field.get(obj));
// 动态调用类的私有方法
Method privateMethod = stuClass.getDeclaredMethod("privateMethod"); // 可以获取类中的所有方法,包括私有方法
privateMethod.setAccessible(true); // 暴力反射,强制开启该方法的访问权限
privateMethod.invoke(obj);
} catch (Exception e) {
e.printStackTrace();
}
}
}
- 以上是反射的一些基础用法,当然反射不止于此,有兴趣可以再深入研究
反射的使用场景?
- 反射是框架的灵魂,平时我们在实际开发中很少运用到反射机制,但是在
Spring
/Mybatis
等框架底层,大量的用到反射技术 - 比如
Spring
中的**IOC
(控制反转),AOP
面向切面编程**,Mybatis
的Mapper
接口代理对象,JDBC
连接数据库时,指定连接数据库驱动类都有用到反射