反射:框架设计的灵魂

*框架:半成品软件。可以在框架的基础上进行软件开发,简化编码

其实,用框架并不一定用得到反射。但是,如果你要开发一套框架供别人使用,就得用到反射。但是,如果我们知道了反射机制,就能在使用框架时游刃有余。

*反射:将类的各个组成部分封装为其他对象,这就是反射机制。

例如:将成员变量封装为Field对象;构造函数-->Constructor对象;成员方法-->Method对象

*获取class对象的方式:

1.Class.forName("全类名");将字节码文件加载进内存,返回Class对象(对应源代码阶段)*多用于配置文件,将类名定义在配置文件中,返回class对象

2.类名.class:通过类名的属性class获取(对应class类对象阶段)*多用于参数的传递

3.对象.getClass():getClass()方法在Object类中定义着 *多用于对象的获取字节码的方式

结论:同一个字节码文件(*.class)在一次程序运行过程中,只会被加载一次,不论通过哪一种方式获取的class对象都是同一个。

 

 好处:1.可以在程序的运行过程中去操作这些对象。例如,String str 这个对象创建之后,str.  后会提示很多方法。这些方法其实就是str对象加载到内存之后,程序运行中程序提供的操作这些对象的方式。

 /*Class对象功能:
    *获取功能:
    1.获取成员变量们:
    *Field[] getFields();---获取所有public 修饰的成员变量
    *Field getField(String name)----获取指定名称的public修饰的成员变量
    *Field[] getDeclaredFields()----获取所有成员边浪
    *Field getDeclaredField(String name)
    *
    *操作:
    *1.设置值    2.获取值
    *2.获取构造方法们
    *Constructor<> getConstructors()
    *Constructor<> getConstructor(类<>..parameterTypes)
    *Constructor<> getDeclaredConstructor(类<>..parameterTypes)
    *Constructor<>[] getDeclaredConstructor()
    *
    *3.获取成员方法们:
    *Method[] getMethods()
    *Method getMethod(String name,类<>...parameterTypes)
    *Method[] getDeclaredMethods()
    *Method getDeclaredMethod(String name,类<>..parameterTypes)
    *
    *4.获取类名
    *String getName()
    */

2.可以解耦。来达到程序的可扩展性。

package cn.itcast.junit;

import java.text.DateFormat.Field;

public class ReflectDemo {
    
    public static void main(String[] args) throws SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException {
        //获取Person的class对象
        Class personClass=Person.class;
        /*1.获取成员变量们:
        *Field[] getFields();
        *Field getField(String name)
        *Field[] getDeclaredFields()
        *Field getDeclaredField(String name)
        **/
        //1.Field[] getFields();---获取所有public 修饰的成员变量
        java.lang.reflect.Field[] Feilds=personClass.getFields();
        for(java.lang.reflect.Field filed:Feilds){
            System.out.println(filed);
            //public java.lang.String cn.itcast.junit.Person.a
        }
        
        //*Field getField(String name)----获取指定名称的public修饰的成员变量
        Person p=new Person();
、 //Field 是对象 。对象就有方法。通过对象的方法完成操作。具体操作参见API文档 java.lang.reflect.Field f
=personClass.getField("a");
、    //此时 f 为获取的 person 类中的String a 参数。如下对 f 进行设置值与赋值 f.set(p,
"这是通过设置成员方法设置的值");//操作成员变量---设置成员变量的值 Object value=f.get(p); System.out.println(value); //*Field[] getDeclaredFields() System.out.println("\n================="); java.lang.reflect.Field[] filed = personClass.getDeclaredFields(); for(java.lang.reflect.Field f1:filed){ System.out.println(f1); } //*Field getDeclaredField(String name) //这里不能访问 d java.lang.reflect.Field f3=personClass.getDeclaredField("d"); Person p2=new Person(); //会报错 //f3.set(p2, "这是通过获取成员变量而设置的值"); //System.out.println(f3.get(p2)); //访问前忽略权限修饰符的安全检查---"暴力反射" f3.setAccessible(true); f3.set(p2, "这是暴力反射后获取成员变量而设置的值"); System.out.println(f3.get(p2)); } }

 

案例:

*需求:写一个“框架”,可以帮我们创建任意类的对象,并且执行其中任意的方法(在不改变该类的任何代码的前提下)。

*实现:

1.配置文件  2.反射

*步骤

1.将需要创建的对象的全类名和需要执行的方法定义在配置文件中

2.在程序中加载读取配置

3.使用反射技术来加载类文件进内存

4.创建对象

5.执行方法

文件列表+配置文件:(实现在不改变任何源代码的前提下,通过改变配置文件来达到获取不同类下的不同方法,并执行)

 

 

 

 

package cn.itcast.reflection;

import java.io.IOException;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Properties;

import org.omg.CORBA.portable.InputStream;

/*
 * 框架类
 * */
public class ReflectTest {
	//可以创建任意类的对象,可以执行任意方法
	public static void main(String[] args) throws IOException, ClassNotFoundException, InstantiationException, IllegalAccessException, SecurityException, NoSuchMethodException, IllegalArgumentException, InvocationTargetException {
		/*前提:不能改变该类的任何代码,可以创建任意类的对象,可以执行任意方法*/
		
		//1.加载配置文件
		//1.1 创建Properties对象
		Properties pro =new Properties();
		//1.2加载配置文件,转换为一个集合
		//1.2.1 获取文件class目录下的配置文件
		ClassLoader classLoader=ReflectTest.class.getClassLoader();
		java.io.InputStream is=classLoader.getResourceAsStream("pro.properties");
		System.out.println(is);
		pro.load(is);
		//2.获取配置文件中配置的数据
		String className=pro.getProperty("className");
		//System.out.println(className);
		String methodName=pro.getProperty("methodName");
		//System.out.println(methodName);
		//3.加载该类进内存
		Class cls=Class.forName(className);
		//创建对象
		Object obj=cls.newInstance();
		//System.out.println(obj);
		//获取方法对象
		Method method=cls.getMethod(methodName);
		//执行方法
		method.invoke(obj);
		
	}
}

 

posted @ 2020-02-12 15:06  远山笑你  阅读(256)  评论(0编辑  收藏  举报