##反射:框架设计的灵魂
框架:半成品软件,可以在框架的基础上进行软件开发,简化代码
反射是什么?
反射:将类的组件部分封装成其他对象,这就是反射机制(更详细的描述:在程序运行状态时,对于任意一个类,都能知道这个类的属性和方法;对于任意一个对象,都能够调用它的任意方法和属性;这种动态获取信息以及动态调用对象方法的功能称为Java反射机制)
好处:1、可以在程序运行的过程中操作这些对象(比如我们使用开发工具进行开发时,开发工具正在运行,创建了一个对象,然后你使用这个对象时能够给你这个 对象包含方法的提示,这就是将这个对象的字节码文件通过类加载器加载到内存并进行了分类封装成对象,然后编辑器通过获取Class类对象来获取方法。“如何获取Class对象,在下边”)
2、解耦,提高程序的可扩展性
Source源码阶段:java文件被编译成字节码文件,通过类加载器被从硬盘加载到了内存
**Class类对象阶段:(java中万物皆对象)在内存中有一个类对象来描述被加载到内存的字节码文件,就是Class类,它将加载到内存的字节码文件中的成员变量、成员方法、构造方法等元素都分类封装成对象(数组)
如何获取Class文件?
获取Class文件(字节码对象)的三种方式:
1、source源代码阶段:Class.forName("全类名:包名+类名"):将字节码文件加载到内存,返回Class对象
*多用于配置文件,将类名放在配置文件,读取配置文件,返回Class对象
2、Class类对象阶段:类名.class:通过类的属性class获取
*多用于参数传递
3、运行时阶段:此时已经可以创建类对象:对象.getClass()。getClass()方法在object类中定义,所有的类都会继承这个类
*多用于对象获取字节码文件的方式
***:同一个字节码文件在一次程序运行中只会被加载一次,所以不管通过那种方式获得的Class对象都是同一个
Class对象的作用:
获取功能:
1、获取成员方法们
*getMethods()
*getMethod(String name, 类<?>... parameterTypes)
*getDeclaredMethod(String name, 类<?>... parameterTypes)
示例:模拟有一个person类,里边有两个写的成员方法: public void eat(){} public void eat(String name){}
Class p=person.class
Method eat1 = p.getMethod("eat");//无参数的
Method eat2 = p.getMethod("eat",String.class);//带参数的
//运行获得的方法
Person p = new person();
eat2.invoke(p,"土豆");
//获得所有public方法,包括person类自己的方法和它继承的类的方法
Method[] methods=p.getMethods();
//获取方法名的方法:method.getName(),结果为String类型
//获得类名的方法:包名+类名
p.getClassName();结果为String类型
2、获取成员变量们
*getFields()
:获取public修饰的成员变量
*getField(String name)
:获取public修饰的成员变量,并指定要获取的成员变量的名字
*get
Declared
Fields()
:获取所有的成员变量,不区分修饰符
*get
Declared
Field(String name)
:获取所有的成员变量,不区分修饰符,
并指定要获取的成员变量的名字
示例:模拟有一个person类,里边有个一个public修饰的a
Class p=person.class
Field a=p.getField("a");
获得之后可以用Field类中的方法对成员变量进行获取值和赋值:
a.get(p);成员变量在类里边
a.set(p,"name");
****在使用get
Declared
Fields
和get
Declared
Field时,可以获得任意类型的变量,但是不能对非public修饰的进行赋值取值操作,如果需要,则应该在
赋值取值操作之前加上a.setAccessible(true),
忽略访问修饰符的安全检查,暴力映射
3、获取构造方法们:构造方法的作用:创建对象
*getConstructor(类<?>... parameterTypes)
*get
Declared
Constructors() :一样有setAccessible(true)
*get
Declared
Constructor(类<?>... parameterTypes)
示例:getConstructor(类<?>... parameterTypes)
模拟一个person类中有:public person(String name,Int age){}
(1)创建带参的
Constructor constructor=p.getConstructor(String.class,int.class);
//通过构造器创建对象
Object obj = constructor.newInstance("张三",23);
(2) 创建不带参的
Constructor constructor=p.getConstructor();
//通过构造器创建对象
Object obj = constructor.newInstance();
创建不带参的第二种方法,直接使用Class对象中的newInstance()方法
Object obj = p.newInstance()
4、获取类名
*getName()
......
实例:
1、person类文件
package com.ruoyi.project.system.domain; public class Person { public void eat(){ System.out.println("eat........."); } }
2、properties文件
classname=com.ruoyi.project.system.domain.Person
method=eat
3、实现文件
import com.ruoyi.project.system.domain.Person; import com.ruoyi.project.system.domain.Student; import java.io.IOException; import java.io.InputStream; import java.lang.reflect.Method; import java.util.Properties; public class newInstance { //需求,模拟一个“框架”,在不改任何代码的前提下可以生成任意的类对象,可以执行任意的对象方法 public static void main(String[] args) throws Exception { //在刚接触反射时,学习了怎么获取Class文件,怎么获取构造方法,怎么获取成员方法,但是有什么用呢? //反射是框架设计的灵魂,灵魂又再什么地方体现的呢? /* //当我第一次想到实现可以生成任意的类对象,可以执行任意的对象方法时,念头就是通过new出类对象 Person person = new Person(); person.eat(); //当需要再次生成一个新的对象时,再在这代码里边改代码,改为: Student student = new Student(); student.study(); //我感觉这样也实现了目标,但是有最重要的一点,就是,作为一个框架,框架里边的代码是不能动的,通过一个框架去实现不同的 //的效果,可以通过配置文件配置数据,像是传递不同参数到一个方法中就会输出不同结果一样 */ //下边为使用反射的方式去完成“框架”的实现 //实现要求:1、配置文件 2、反射 /* * 步骤:1、将需要创建的对象的全类名和需要执行的方法定义在配置文件中 * 2、在程序中读取配置文件 * 3、使用反射技术加载类文件进内存 * 4、创建对象 * 5、执行方法 * */ //1、加载配置文件(Properties类中有一个load方法可以将properties文件加载进来) //1.1创建properties对象 Properties pro=new Properties(); //1.2加载配置文件 //1.2.1获取class目录下的配置文件,方法:通过本类获取Class文件,进而去获取类加载器,类加载器加载项目,所以可以找到properties文件 ClassLoader classLoader = newInstance.class.getClassLoader(); InputStream proResource = classLoader.getResourceAsStream("pro.properties"); pro.load(proResource); //2、获取配置文件的数据 String classname = pro.getProperty("classname"); String method = pro.getProperty("method"); //3、通过反射加载配置文件中的类进内存 Class aClass = Class.forName(classname); //4、创建对应的类对象 Object obj = aClass.newInstance(); //5、获取配置文件的指定方法对象 Method method1 = aClass.getMethod(method); //6、执行方法 method1.invoke(obj); } }