概念
在程序运行时动态加载一个类
- 对于任意一个类,都能够知道这个类的属性和方法
- 对于任意一个对象,都能够调用它的任何方法和属性
关键字:运行时、动态
补充知识点
- 静态编译:在编译时确定类型,绑定对象
- 动态编译:运行时确定类型,绑定对象
用途
主要用于各种框架之中
case1:JDBC
项目底层有时是用mysql,有时用oracle,需要动态地根据实际情况加载驱动类
- 通过Class.forName()加载数据库的驱动程序 (通过反射加载,前提是引入相关了Jar包)
- 通过 DriverManager 类进行数据库的连接,连接的时候要输入数据库的连接地址、用户名、密码
- 通过Connection 接口接收连接
case2:Spring XML装配bean
- 将程序内所有 XML 或 Properties 配置文件加载入内存中
- Java类里面解析xml或properties里面的内容,得到对应实体类的字节码字符串以及相关的属性信息
- 使用反射机制,根据这个字符串获得某个类的Class实例
- 动态配置实例的属性
原理
预备知识:java类加载机制:https://blog.csdn.net/raichen_wang/article/details/95916851
JAVA语言编译之后会生成一个.class文件,反射就是通过字节码文件找到某一个类、类中的方法以及属性等。
反射的实现主要借助以下四个类:
- Class:类的对象
- Constructor:类的构造方法
- Field:类中的属性对象
- Method:类中的方法对象
使用
测试用例
@Data
@Builder
public class Student {
private String name;
private int age;
public Student() {
}
public Student(int age) {
this.age = age;
}
public Student(String name) {
this.name = name;
}
public Student(String name, int age) {
this.name = name;
this.age = age;
}
private void showArg(String arg){
System.out.println(arg);
}
public void showArg1(String arg){
System.out.println(arg);
}
}
获取Class对象
Student student = Student.builder().name("BaLeMengGan").age(22).build();
// 方式一
Class clazz1 = Student.class;
// 方式二
Class clazz2 = student.getClass();
// 方式三
try {
Class clazz3 = Class.forName("compare.Student");
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
获取构造方法
获取批量的方法:
public Constructor[] getConstructors():所有"公有的"构造方法
public Constructor[] getDeclaredConstructors():获取所有的构造方法(包括私有、受保护、默认、公有)
获取单个的方法
public Constructor getConstructor(Class... parameterTypes):获取单个的"公有的"构造方法:
public Constructor getDeclaredConstructor(Class... parameterTypes):获取"某个构造方法"可以是私有的,或受保护、默认、公有;
调用构造方法:
Constructor-->newInstance(Object... initargs)
// 所有的构造方法(包括:私有、受保护、默认、公有)
for (Constructor con : clazz1.getDeclaredConstructors()) {
System.out.println(con);
}
// 调用构造方法
try {
Constructor con1 = clazz1.getConstructor(String.class);
Object s1 = con1.newInstance("wang");
System.out.println(s1);
} catch (Exception e) {
e.printStackTrace();
}
获取成员变量
// 获取成员变量(包括私有、受保护、默认的)
for (Field field : clazz1.getDeclaredFields()) {
System.out.println(field);
}
Student s1=new Student();
try {
Field f1 = clazz1.getDeclaredField("name");
// 解除私有限定
f1.setAccessible(true);
f1.set(s1,"zhang");
System.out.println(s1);
} catch (Exception e) {
e.printStackTrace();
}
获取成员方法
// 获取成员方法
for (Method method : clazz1.getDeclaredMethods()) {
System.out.println(method);
}
try {
// 获取一个成员方法,既要传入方法名,又要传入参数类型(因为有重载)
Method m1 = clazz1.getDeclaredMethod("showArg", String.class);
m1.setAccessible(true);
m1.invoke(s1, "haha");
} catch (Exception e) {
e.printStackTrace();
}