反射
- 框架:半成品软件,可以在框架的基础上进行软件开发,简化编码
- 反射:将类的各个组成部分封装为其他对象,这就是反射机制
- 好处:
(1)可以在程序运行过程中,操作这些对象
(2)可以解耦,提高程序的可扩展性
获取Class对象的方式:
(1)Class.forName(“全类名”):对应Source阶段,将字节码文件加载进内存,返回Class对象
多用于配置文件,将类名定义在配置文件中,读取文件,加载类
(2)类名.class:对应于Class阶段,通过类名的属性class获取
多用于参数传递
(3)对象.getClass():对应于Runtime阶段,getClass方法在Object类中定义
多用于对象的获取字节码文件
(4)结论:同一个字节码文件(*.class)在一次程序执行过程中,只会被加载一次,不论通过哪一种方式获取的Class对象都是同一个
package reflect; import domain.Person; public class ReflectDemo1 { /** 获取Class对象的方式: (1)Class.forName("全类名"):对应Source阶段,将字节码文件加载进内存,返回Class对象 (2)类名.class:对应于Class阶段,通过类名的属性class获取 (3)对象.getClass():对应于Runtime阶段,getClass方法在Object类中定义 */ public static void main(String[] args) throws Exception{ //全类名 Class cls1 = Class.forName("domain.Person"); System.out.println(cls1); //类名.class Class cls2 = Person.class; System.out.println(cls2); //对象.getClass() Person p = new Person(); Class cls3 = p.getClass(); System.out.println(cls3); //判断是否为同一个对象 System.out.println(cls1 == cls2); System.out.println(cls1 == cls3); } }
Class对象功能
不加Declared,只能访问public修饰;加了Declared,所有都可以获取,不考虑修饰符
(1)获取成员变量:
(2)获取构造方法
(3)获取成员方法
(4)获取类名:全类名
Person类:
package domain; public class Person { private String name; private int age; public String a; protected String b; String c; private String d; @Override public String toString() { return "Person{" + "name='" + name + '\'' + ", age=" + age + ", a='" + a + '\'' + ", b='" + b + '\'' + ", c='" + c + '\'' + ", d='" + d + '\'' + '}'; } 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 Person() { } public Person(String name, int age) { this.name = name; this.age = age; } public void eat(){ System.out.println("eat"); } public void eat(String food){ System.out.println("eat " + food); } }
Field:成员变量
(1)设置值
(2)获取值
(3)忽略访问权限修饰符的安全检查,设置为true:暴力反射
//Field package reflect; import domain.Person; import java.lang.reflect.Field; public class ReflectDemo02 { public static void main(String[] args) throws Exception { //1.获取Person的Class对象 Class personClass = Person.class; //2.获取成员变量 getFields,获取public修饰的成员变量 Field[] fields = personClass.getFields(); for (Field field : fields) { System.out.println(field); } System.out.println("------------"); Field a = personClass.getField("a"); Person p = new Person(); //获取成员变量a的值 Object value = a.get(p); System.out.println(value); System.out.println("------------"); //设置a的值 a.set(p, "张三"); System.out.println(p); System.out.println("------------"); //获取所有成员变量 getDeclaredFields,不考虑修饰符 Field[] declaredFields = personClass.getDeclaredFields(); for (Field declaredField : declaredFields) { System.out.println(declaredField); } System.out.println("------------"); Field d = personClass.getDeclaredField("d"); //忽略修饰符的安全检测 d.setAccessible(true); //暴力反射 Object value2 = d.get(p); System.out.println(value2); System.out.println("------------"); } }
Constructor:构造方法
创建对象
如果使用空参构造方法创建对象,操作可以简化:Class对象的newInstance方法
//Constructor package reflect; import domain.Person; import java.lang.reflect.Constructor; public class ReflectDemo03 { public static void main(String[] args) throws Exception { //1.获取Person的Class对象 Class personClass = Person.class; //2.获取构造方法 //有参 Constructor constructor = personClass.getConstructor(String.class, int.class); System.out.println(constructor); //无参 Constructor constructor1 = personClass.getConstructor(); System.out.println(constructor1); //3.创建对象 Object person = constructor.newInstance("张三", 23); System.out.println(person); Object person1 = constructor1.newInstance(); System.out.println(person1); //无参简化 Object person2 = personClass.newInstance(); System.out.println(person2); } }
Method:成员方法
(1)执行方法
(2)获取方法名称
//Method package reflect; import domain.Person; import java.lang.reflect.Constructor; import java.lang.reflect.Method; public class ReflectDemo04 { public static void main(String[] args) throws Exception { //1.获取Person的Class对象 Class personClass = Person.class; //2.获取指定名称的方法,无参 Method eat = personClass.getMethod("eat"); //获取指定方法,有参 Method eat1 = personClass.getMethod("eat", String.class); Person p = new Person(); //3.执行方法 eat.invoke(p); eat1.invoke(p, "apple"); //获取所有public修饰的方法,包含Object类的方法 Method[] methods = personClass.getMethods(); for (Method method : methods) { String name = method.getName(); System.out.println(name); System.out.println(method); } } }
案例
- 需求:写一个“框架”,不能改变该类的任何代码的前提下,可以创建任意类的对象,并且执行其中任意方法
- 实现
(1)配置文件
(2)反射 - 步骤
(1)将需要创建的对象全类名和需要执行的方法定义在配置文件中
(2)在程序中加载读取配置文件
(3)使用反射技术来加载类文件进内存
(4)创建对象
(5)执行方法
//配置文件 pro.properties //file类型 className = domain.Person methodName = eat
package reflect; import java.io.InputStream; import java.lang.reflect.Method; import java.util.Properties; public class ReflectTest { public static void main(String[] args) throws Exception{ //1.加载配置文件 //1.1创建Properties对象 Properties pro = new Properties(); //1.2加载配置文件,转化为一个集合 //获取class目录下的配置文件 ClassLoader classLoader = ReflectTest.class.getClassLoader(); InputStream is = classLoader.getResourceAsStream("pro.properties"); pro.load(is); //2.获取配置文件中定义的数据 String className = pro.getProperty("className"); String methodName = pro.getProperty("methodName"); //3.加载该类进内存 Class cls = Class.forName(className); //4.创建对象,无参构造 Object obj = cls.newInstance(); //5.获取方法对象 Method method = cls.getMethod(methodName); //6.执行方法 method.invoke(obj); } }