反射
什么是反射:
反射是Java语法的一种高级特性,在“运行期间”对Java的类型信息进行检查,操作处理。例如:加载JDBC驱动类,Mybatis动态处理resultType,Spring根据配置创建Bean对象等使用场景都用反射实现
常见的反射操作:
- 获取Class类型信息
- 执行构造方法创建对象
- 调用实例方法
- 通过成员变量保存值和获取值
Class类
Class对象用于保存一个类的类型信息,它是反射的入口操作
获取Class对象的三种方式:
-
通过类名:
Class cls = Book.class;
-
通过forName()方法:
Class cls = Class.forName("com.dong.Book");
-
通过对象:
Class cls = new Book().getClass();
类只加载一次,三个方法获取同一个类的Class对象,输出相同
Constructor类
代表一个类中的构造方法(构造器),用于创建“目标对象”
- 获取Constructor构造方法的方式
-
Class对象.getConstructor() 获取无参构造方法
Class cls = Book.class;Constructor constructor1 = cls.getConstructor(); // 获取无参构造方法
-
Class对象.getConstructor(Class…) 获取有参构造方法
Class cls = Book.class;// 获取有参构造方法,在Book类中存在有参构造方法 // 参数列表为:String,String,double,int Constructor constructor2 = cls.getConstructor(String.class,String.class,double.class,int.class);
- 执行Constructor构造方法的方式
-
Constructor对象.newInstance() 执行无参构造方法
// 执行无参构造方法,创建目标对象 Object obj = constructor1.newInstance();
-
Constructor对象.newInstance(值…) 执行有参构造方法
// 执行有参构造方法,创建目标对象 Object obj = constructor2.newInstance("额尔古纳河右岸","迟子建",12.5,100);
-
获取所有的构造方法
Class<Book> cls = Book.class; Constructor[] constructors = cls.getConstructors();
总结:创建目标对象的方法(3种):
-
通过Class对象:
Class<Book> cls = Book.class; Object obj = cls.newInstance();
-
通过无参构造方法
-
通过有参构造方法
Field类
代表一个类中的成员变量(字段),用于为“目标对象”保存值和获取值
- 获取Field成员变量的方式
-
获取
public
修饰的成员变量:Class对象.getFields()Class cl = Book.getClass(); Field[] fields = cl.getFields();
-
获取
public/private
修饰的成员变量:Class对象.getDeclaredFields()Class cl = Book.getClass(); Field[] fields = cl.getDeclaredFields();
- 使用Field成员变量的方式
-
Class对象.getField(成员变量名称):
public
修饰的成员变量Class cl = Book.getClass(); Field[] fields = cl.getFields("bookName");
-
Class对象.getDeclaredField(成员变量名称):
public\private
修饰的成员变量Class cl = Book.getClass(); Field[] fields = cl.getDeclaredFields("bookName");
-
给Filed成员变量赋值:
Field对象.set(目标对象,Value);
// 获取需要创建的对象类型信息 Class bookClass = Book.class; // 创建对象 Object bookObj = bookClass.newInstance(); // 获取该类型中bookName成员变量 Field bookNameField = bookClass.getDeclaredField("bookName");// book对象.bookName = "舒克和贝塔" bookNameField.setAccessible(true); // 由于Book类中bookName是私有的,所以需要设置 bookNameField.set(bookObj, "舒克和贝塔");
setAccessible:
封装时,类的成员变量私有,将Field对象的accessible标志设置为ture表示:反射的对象在使用时应该取消 Java 语言访问检查;设置为false表示:反射的对象应该实施 Java 语言访问检查
-
获取成员变量名称并获取变量值
获取成员变量名称:Field对象.getName();
获取变量值:Field对象.get(目标对象名);
例:
public static void main(String[] args) throws NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {// 获取类型的信息对象Class<Book> cls = Book.class;// 创建目标对象Constructor constructor = cls.getConstructor(String.class,String.class,double.class,int.class);Object obj = constructor.newInstance("额尔古纳河右岸","迟子建",12.6,100);show(obj); }public static void show(Object obj) {try {Class cl = obj.getClass(); Field[] fields = cl.getDeclaredFields();for(Field f : fields) {f.setAccessible(true);System.out.println("属性"+f.getName()); // 获取成员变量属性System.out.println("属性值:"+f.get(obj)); // 获取变量属性值}} catch (SecurityException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();} catch (IllegalAccessException e) {e.printStackTrace();} }
Method类
代表一个类中的方法,用于调用执行该方法
- 获取Method方法的方式
-
获取指定名称和参数列表的Method:Class对象.getMethod(String name,Class…parameterTypes)
在调用时,需要传入方法名,以及参数列表类型,eg: Class cls = Book.class; Method method = cls.getMethod("read",String.class,String.class);
-
获取所有的Method方法:Class对象.getMethods();
Class cls = Book.class; Method[] methods = cls.getMethods();for(Method m : methods) {System.out.println(m);System.out.println("访问修饰符::"+m.getModifiers()); System.out.println("返回值类型:"+m.getReturnType());// 参数列表为一个Parameter类型的数组System.out.println("参数列表:");for(Parameter p : m.getParameters()) {System.out.println(p);}System.out.println("方法名称:"+m.getName());System.out.println(); }
- getModifiers():获取访问修饰符
- getReturnType():获取返回值类型
- getParameters():获取参数列表
- getName():获取方法名称
- 执行Method方法的方式
Method对象.invoke(目标对象,方法参数):
eg:读取配置文件调用方法
config.txt:
com.dong.Task
execute
Task类:
public class Task {public String execute(String id) {System.out.println("ִ执行流水号:" + id);System.out.println("ִ执行了Task任务类的excute方法!!!");return "ok";}
}
Job类:
public class Job {public String run(String id) {System.out.println("执行流水号:" + id);System.out.println("ִ执行了Job任务类的run方法!!!");return "success";}
}
Main方法:
import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.nio.file.Files;
import java.nio.file.Paths;
import java.util.List;
import java.util.UUID;public class reflex07 {public static void main(String[] args) throws IOException, ClassNotFoundException, NoSuchMethodException, SecurityException, InstantiationException, IllegalAccessException, IllegalArgumentException, InvocationTargetException {// 读取配置文件调用方法,修改配置文件中内容执行不同的方法List<String> configList = Files.readAllLines(Paths.get("f:\\config.txt"));String className=configList.get(0);String methodName=configList.get(1);// 获取类信息Class<?> cl = Class.forName(className);// 获取方法Method method = cl.getMethod(methodName, String.class);// 执行方法Object obj = cl.newInstance(); // 创建目标对象Object returnVal = method.invoke(obj, UUID.randomUUID().toString()); // 调用方法System.out.println("返回值:"+returnVal);}
}
通过Method对象.invoke(目标对象,参数列表)调用方法