这是关于反射机制的一篇笔记。 视频教程地址
-
概念:将类的各个组成部分封装为其他对象,就是反射机制
-
好处:
- 可以在程序运行中操作这些对象
- 可以解耦,提高程序的可扩展性。
-
获取class对象的方式:
-
Class.forName("全类名")
:将字节码文件加载进内存,返回class对象。- 多用于配置文件,将类名定义在配置文件中,读取文件,加载类。
-
类名.class 通过类名的属性class获取
- 多用于参数的传递
-
对象.getClass()
:getClass()
方法在Object类中定义着。- 多用于对象的获取字节码的方式
-
同一字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的class对象都是同一个。
-
代码
//1.Class.forName("全类名"); Class cls1 = Class.forName("com.qmh.domain.Person"); System.out.println(cls1); //2.类名.class Class cls2 = Person.class; System.out.println(cls2); //3.对象.getClass() Person p = new Person(); Class cls3 = p.getClass(); System.out.println(cls3);
-
-
Class对象功能:
-
获取成员变量们
public Field[] getFields()
:获取所有public修饰的成员变量public Field getField(String name)
::获取指定名称的public修饰的成员变量public Field[] getDeclaredFields()
:获取所有的成员变量,不考虑修饰符public Field getDeclaredField(String name)
:获取指定名称的成员变量,不考虑修饰符
-
获取构造方法们
public Constructor<?>[] getConstructors()
public Constructor<T> getConstructor(类<?>... parameterTypes)
public Constructor<?>[] getDeclaredConstructors()
public Constructor<T> getDeclaredConstructor(类<?>... parameterTypes)
-
获取成员方法们
public Method[] getMethods()
public Method getMethod(String name,类<?>... parameterTypes)
public Method[] getDeclaredMethods()
public Method getDeclaredMethod(String name,类<?>... parameterTypes)
-
获取类名
String getName()
//获取类名 String className = personClass.getName(); System.out.println(className);
-
-
Field:成员变量
-
操作:
- 获取值
public Object get(Object obj)
- 设置值
public void set(Object obj,Object value)
- 忽略访问权限修饰符的安全检查
name.setAccessible(true); //暴力反射
- 获取值
-
代码:
//1.获取Person的Class对象 Class<Person> personClass = Person.class; //2.获取成员变量们 Field[] fields = personClass.getFields(); for(Field field:fields){ System.out.println(field); } System.out.println("--------------"); //3.获取指定名称的成员变量 Field a = personClass.getField("a"); //获取a的值 Person p = new Person(); Object o = a.get(p); System.out.println(o); //设置a的值 a.set(p,"张三"); System.out.println(p); System.out.println("--------------"); //获取所有的成员变量,不考虑修饰符 Field[] declaredFields = personClass.getDeclaredFields(); for(Field declaredField : declaredFields){ System.out.println(declaredField); } // 访问某个私有成员变量, Field name = personClass.getDeclaredField("name"); //忽略访问权限符的安全检查 name.setAccessible(true); //暴力反射 Object o1 = name.get(p); System.out.println(o1); name.set(p,"李四"); System.out.println(p);
-
-
Constructor:构造方法
- 创建对象
public T newInstance(Object... initargs)
- 如果使用空参数构造方法创建对象,操作可以简化:Class对象的
newInstance()
方法 - 代码:
//1.获取Person的Class对象 Class<Person> personClass = Person.class; //获取某个构造方法 Constructor<Person> constructor = personClass.getConstructor(String.class, int.class); System.out.println(constructor); //创建对象 Person person = constructor.newInstance("张三", 18); System.out.println(person); System.out.println("--------------"); //空参构造方法 Person person2 = personClass.newInstance(); System.out.println(person2);
- 创建对象
-
Method 方法对象
- 执行方法
public Object invoke(Object obj,Object... args)
- 获取方法名称:
method.getName()
- 代码:
//1.获取Person的Class对象 Class<Person> personClass = Person.class; // 获取空参方法 Method eat = personClass.getMethod("eat"); Person p = new Person(); //执行方法 eat.invoke(p); //获取带参方法 参数:方法名和参数类 Method eat1 = personClass.getMethod("eat", String.class); //执行方法,传入对象和参数 eat1.invoke(p, "饭"); //获取所有public修饰的方法 Method[] methods = personClass.getMethods(); for(Method method:methods){ System.out.println(method); String name = method.getName(); System.out.println(name); }
- 执行方法
-
案例:
-
需求:写一个“框架”,不能改变该类的任何代码,可以帮助我们创建任意类的对象,并执行其中任意类的方法
-
实现:
- 配置文件
- 反射
-
步骤
- 将需要创建的对象的全类名和需要执行的方法定义在配置文件中
- 在程序中加载配置文件
- 使用反射技术来加载类文件进内存
- 创建对象
- 执行方法
-
配置文件内容:
className = com.qmh.domain.Student methodName = sleep
-
测试代码:
public static void main(String[] args) throws Exception { //不能改变该类的任何代码,可以创建任意类的对象,可以执行任意方法 /*Person p = new Person(); p.eat();*/ //1.加载配置文件 //1.1 创建Properties对象 Properties pro = new Properties(); //1.2加载配置文件,转换为一个集合 pro.load(Resources.getResourceAsStream("pro.properties")); //2.获取配置文件中定义的数据 String className = pro.getProperty("className"); String methodName = pro.getProperty("methodName"); //3.加载该类进内存 Class cls = Class.forName(className); //4.创建对象 无参构造函数 Object o = cls.newInstance(); //5.获取方法对象 Method method = cls.getMethod(methodName); //6.执行方法 method.invoke(o); }
-