反射技术的浅析

一、反射中的基本概念

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


猜你喜欢

转载自blog.csdn.net/biedazhangshu/article/details/49280133