一、反射中的基本概念
1、反射的应用场景
1、当一个应用程序定义完之后,后期如果要使用更多的对象,而对象不确定的时候,我们可以对外提供配置文件,
2、反射技术的出现在不修改程序源代码的前提下,提高了程序的扩展性。
2、反射的由来
以前获取对象的时候,需要有确定的类,利用反射技术可以动态的获取类以及类中的成员,并可以调用该类的成员。 反射技术中:没有类,给什么类就new什么对象,无论new什么对象,都需要先获取字节码文件,如果想要操作字节码文件,只需要得到字节码文件对象二、反射的使用
1、获取Class(字节码文件)对象
方式一:Object getClass()方法。
反射技术中不合适,因为反射技术中不明确具体类//调用getClass()首先要有对象
Person p = new Person();
Class clazz = p.getClass()
方式二:使用数据类型的.class属性
所有的数据类型都有自己对应的Class对象,并且每一个数据类型都有一个默认的静态属性,.class,用该属性就可以获取到字节码文件对象 Class clazz = Person.class;方式三:使用Class类中的forName()方法
通过类的名称(包含包名的完整名称)就可以获取对应字节码文件对象,适合使用在反射中获取Class对象 String className = "com.domain.Person";Class clazz = Class.forName(className);根据名字去classpath下去找对应的类文件,项目中设置了classpath,自动加载类进内存。
2、动态的创建对象
newInstance() :首先根据给定的类名称获得该类的Class对象,然后使用该方法创建此Class对象所表示的类的一个新实例。 newInstance()方法默认调用该类的空参数构造函数,如果没有空参构造函数,将会产生异常 java.lang.InstantiationException,所以一般被反射的类通常都有空参数的构造函数。public static void getObject(){
//1,根据给定类名获取Class对象
String className = "com.domain.Person";
Class clazz = Class.forName(className);
//2,创建一个Person对象
Object obj = clazz.newInstance();
}
3、根据指定的构造器动态创建对象
思路:先获取指定的构造函数。再通过该构造函数进行实例化
getConstructor(Class<?>... parameterTypes) 方法返回构造器对象 parameterTypes :参数数组
public static void getObject() throws Exception{
String className = "com.domain.Person";
Class clazz = Class.forName(className);
//1,通过Class获取指定构造函数,比如带两个参数的构造方法
Constructor cons = clazz.getConstructor(String.class , int.class);参数:类型对象
//2,通过指定的构造器对象进行对象的初始化
Object obj = cons.newInstance("lisi",23);
}
4、动态的获取字段
方法介绍
使用Class对象的方法:Field getField(String name);返回一个Field对象,该对象反映此 Class 对象所表示的类或接口的指定公共成员字段Field getDeclaredField(String name);返回一个Field对象,该对象表示此Class对象所表示的类或接口的指定已声明字段,包含私有的
AccessibleObject 类是Field、Method和Constructor 对象的基类,可以取消默认访问控制检查的能力。
示例
<span style="font-family:SimSun;"><span style="white-space:pre"></span>public static void getField() throws Exception{
String className = "com.domain.Person";
Class clazz = Class.forName(className);
//获取指定age字段
//Field field = clazz.getField("age");//该方法只获取公有字段
Field field = clazz.getDeclaredField("age");//获取所有字段
//要对非静态的字段操作必须有对象
Object obj = clazz.newInstance();
field.setAccessible(true);//暴力访问
field.set(obj, 40);
System.out.println(field.get(obj));
}</span>
String className = "com.domain.Person";
Class clazz = Class.forName(className);
//获取指定age字段
//Field field = clazz.getField("age");//该方法只获取公有字段
Field field = clazz.getDeclaredField("age");//获取所有字段
//要对非静态的字段操作必须有对象
Object obj = clazz.newInstance();
field.setAccessible(true);//暴力访问
field.set(obj, 40);
System.out.println(field.get(obj));
}</span>
public static void getField() throws Exception{
String className = "com.domain.Person";
Class clazz = Class.forName(className);
//获取指定age字段
//Field field = clazz.getField("age");//该方法只获取公有字段
Field field = clazz.getDeclaredField("age");//获取所有字段
//要对非静态的字段操作必须有对象
Object obj = clazz.newInstance();
field.setAccessible(true);//暴力访问
field.set(obj, 40);
System.out.println(field.get(obj));
}
常见异常:
NoSuchFieldException:没有找到带有指定名的字段NullPointerException:name 为null
5、动态的获取方法
1,概念简介
Method类提供关于类或接口上单独的某个方法(以及如何访问该方法)的信息。可以为类方法或实例方法(包括抽象方法)。Object invoke(Object obj, Object... args);通过反射调用底层方法的方法
参数:obj 用于调用底层方法的对象args 用于调用方法的参数
返回:使用参数args在obj上指派该对象所表示方法的结果
Method getMethod(String name , Class<?>... parameterTypes)返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
name 方法名 parameterTypes 参数列表返回:与指定的name和parameterTypes匹配的Method对象
2,方法实例
<span style="white-space:pre"></span>public static void getMethod() throws Exception{
String className = "com.domain.Person";
Class clazz = Class.forName(className);
//反射方法,非静态,无参数的show方法
Method method = clazz.getMethod("show",null);
//创建用于调用method方法的对象
Object obj = clazz.newInstance();
method.invoke(obj , null);
}
三、反射应用实例
配置文件中usb1 = com.reflect.test.KeyByUSB
usb2 = com.reflect.test.MouseByUSB
//USB接口
package com.reflect.test;
public interface USB{
/**
*定义开启
*/
void open();
/**
*定义关闭
*/
void close();
}
//笔记本类
package com.reflect.test;
public class NoteBook{
/**
*运行功能
*/
public void run(){
System.out.println("notebook run");
}
/**
*使用USB设备
*/
public void useUSB(USB usb){
if(usb!=null){
usb.open();
usb.close();
}
}
}
测试类
package com.reflect.test;
public class NoteBookMain{
public static void main(String[] args){
NoteBook book = new NoteBook();
book.run();
//对外提供配置文件
File configFile = new File("usb.properties");
if(!configFile.exists){
configFile.createNewFile();
}
//读取流和配置文件相关联
FileInputStream fis = new FileInputStream(configFile);
Properties prop = new Properties();
//将流中的数据加载到prop
prop.load(fis);
for(int x = 1 ; x<=prop.size();x++){
String className = prop.getProperty("usb"+x)
//对指定的类进行加载
Class clazz = Class.forName(className);
USB usb = (USB)clazz.newInstance();
book.useUSB(usb);
}
}
}
键盘类
package com.reflect.test;
public class KeyByUSB implements USB {
@Override
public void close(){
System.out.println("Key close");
}
@Override
public void open(){
System.out.println("key open");
}
}
鼠标类
package com.reflect.test;
public class MouseByUSB implements USB {
@Override
public void close(){
System.out.println("Mouse close");
}
@Override
public void open(){
System.out.println("Mouse open");
}
}