反射技术的浅析

时间:2022-08-27 18:46:33

一、反射中的基本概念

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>

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");
}
}