第一讲 反射应用场景&特点
1、反射定义
动态的获取指定类以及动态的调用类中的内容。给程序使用者提供了一个可以自己定制功能的接口,提高了程序的扩展性。
2、实现方式
通过配置文件的方式,程序使用者在配置文件中设置自定义的类名,程序内部调用该配置文件,获取该类的字节码文件及类对象,进而调用类中的成员方法和成员变量,实现了成语与使用者的交互。
其中,实现接口的类由程序使用者自己定义。
3、图解示例
第二讲 获取字节码文件对象&创建类对象
1、Class类
Class——用来描述字节码文件的类,反射的技术就是通过该类来实现的。
该类中提供和获取类字节码文件对应类中的构造函数对象、一般方法对象、字段对象的方法。
2、获取字节码文件的对象的方式
方式一:通过Object类中的getClass()方法获取,需要通过类的对象调用。
示例如下:获取Person类中的字节码文件对象
Person p = new Person();——创建类对象
Class clazz = p.getClass();——通过Object中的方法getClass()获取字节码文件对象。
说明:这种方法需要明确具体的类,并创建该类的对象,比较麻烦。
方式二:任何数据类型都具备一个静态的属性”.class”,可以用类直接调用:Class clazz = Person.class;
说明:该方法相对于方式一更加简单,但还是要明确类名和类中的静态成员,还是不够扩展。
方式三:Class类中的forName(String className)方法,其中的className要完整,包括包名(如,cn.itcast.bean.Person)。
代码实现如下:
String className = “cn.itcast.bean.Person”;——这里的类型可以通过配置文件读取到,由程序使用者自己定义类,并将类型输入到配置文件指定位置,传入程序中。
Class clazz = forName(className);——程序通过从配置文件上获取到的类名来获取该类对应的字节码文件对象。
说明:只通过给定的类的字符串名称就可以获取该类,扩展性更强。
以上三种方式代码示例:
第三讲 获取构造函数&动态创建类对象
1、概述
要创建类对象就需要调用类的构造函数(类内部定义方法获取对象的情况除外),Class类中定义了获取类对象的方法newInstance(),该方法调用了类中的无参数构造函数;
代码实现如下:
2、调用类中有参数构造函数来创建类对象
Class类中的newInstance()方法只能调用类中的无参数构造函数,要想通过类中的有参数构造函数来创建类对象,就要先获取类中的有参数构造函数。
实现方法:
先获取类中带参数的构造函数对象(利用
getConstructor(String.class,int.class)方法),根据自己需要来确定参数列表;
然后通过获取到的构造函数对象调用方法newInstance(String str,int i),来调用类中带参数构造函数来创建类对象,代码实现如下:
第四讲 获取类中的方法
1、概述
我们获取到类的字节码文件对象后,可以通过该对象获取中一般方法的对象,然后用方法对象获取一般方法。
2、获取并调用一般方法
- 获取字节文件对象;
Class clazz = Class.forName(className);
- 根据方法名获取方法对象;
Method method = clazz.getMethod(methodName,String.class,int.class);
取空参数函数:clazz.getMethod(methodName,null)
- 调用方法;
Object obj = clazz.newInstance();——需先创建类对象。
methods.invoke(obj,”zhangsan”,”23”);
调用静态方法:methods.invoke(null,”zhangsan”,”23”);——调用静态方法,不需要对象。
总结:通过字节码文件对象来获取方法对象,通过方法类中的invoke()来调用方法。如果调用的是非静态方法,则invoke()实际参数中要有类对象;若,调用的是静态方法,则不需要类对象,用null代替。没有参数的地方,用null代替。
第五讲 获取字段&暴力访问
1、概述
Class类中定义了获取字段对象的方法,获取了字段对象,就可以用它来访问类中的字段(获取、设置等)。
2、获取并设置字段步骤
- 获取字节码文件对象;——Class.forName()
- 用字节码文件对象调用Class中的方法getField(fieldName)或
getDeclaredField(fieldName)来获取自定名称的字段对象;
getField(fieldName)——获取的是共有字段的对象;
getDeclaredField(fieldName)——获取的是所以字段的对象;
- 设置字段;——field.set(obj,90);需要指定类对象。
说明:若为私有字段,此处设置字段值会失败,我们可以通过暴力访问的方式,将访问权限检查取消,再设置字段的值。
3、暴力访问类中的私有成员——用AccessiableObject类
定义:AccessiableObject类是Field类、Method类、Constructor类的父类,该类中方法setAccessible()可以取消类中成员的权限检查,以使得Field类对象、Method类对象、Constructor类对象能够访问类中的私有字段、方法;
实现代码:
Field.setAccessible(true);——取消对字段的的权限访问,即暴力访问。
field.set(obj,90);——设置私有字段值。
说明:程序将成员声明成私有的,试想把该成员保护起来,所以一般不访问私有成员。
第六讲 反射应用案例
演示笔记本电脑使用USB接口示例:
需求:笔记本电脑调用接入USB接口的设备,要求不同的设备执行不同的方法。
思路:
1、电脑需要使用一些外围设备,如鼠标、键盘、U盘等,为了提高扩展性,应该降低这些设备和电脑的耦合性,因此就需要引入接口的技术(不管接入什么设备,只要符合USB规则,就可以被电脑使用)。
2、然而,如果USB接口接入了新的设备,就需要修改原始代码,才能调用新的设备,这样很麻烦,因此,可以引入反射的技术,提供一个配置文件。
3、我们只需要将接入设备的功能定义好,并且在配置文件中传入设备的信息,在不修改原代码的情况下,电脑也能使用接入的设备。
代码演示: