Day16:反射技术
反射技术是Java语言中的核心技术之一,也是Java语言能够拥有自己生命力的技术之一。反射技术使得类拥有了活力,能够动态生成对象,调用类中的任意成员即使是private修饰的,通常使用反射技术的是在用户拥有定制权利的地方,例如连接数据库的配置文件、Spring配置文件、Android配置文件等等,只要用户在配置文件中输入相对应的参数,虚拟机就可以根据配置文件找到相对应的类对象然后生成用户希望的效果。
/* * 反射技术:动态的获取类以及类中的成员,并可以调用该类成员。 * 以前是有什么类,就new什么对象。没有类,给什么类就new什么对象。 * * 无论new什么对象,都需要先获取字节码文件。 * 如何获取呢?发现java已对字节码文件进行了描述用的Class类完成的。 * * 如何获取一个字节码文件的对象呢? *
* 方式一:Object getClass();方法。发现在反射技术里,该方法不合适。反射技术不明确具体类。 * * 方式二:所有的数据类型都有自己对应的Class对象。表示方式很简单。 * 每一个数据类型都有一个默认的静态的属性。.class,用该属性就可以获取到字节码文件对象。 * 虽然不用对象调用了,还是要用具体的类调用静态属性。 * * * 方式三:在Class类中的找到了forName方法。通过名称就可以获取对应的字节码文件对象。重点。 *
*/
通常情况下,在写Bean类时,会留下一个无参构造方法,这个方法通常是给反射时候用的,方便在获取类对象时不传入任何参数进行实例化。下面,我们将利用一个笔记本和USB接口进行一次演示:
/** *我们首先定义一个笔记本类 */ public class NoteBook { /** * 运行功能。 */ public void run(){ System.out.println("notebook run"); } /** * 使用usb设备。 */ public void useUSB(USB usb){ if(usb!=null){ usb.open(); usb.close(); } } }
/** *然后我们再去定义USB接口 */ public interface USB { /** * 定义关闭。 */ void close(); /** * 定义开启。 */ void open(); }
/** *在USB接口处定义鼠标 */ public class MouseByUSB implements USB { @Override public void close() { System.out.println("mouse close"); } @Override public void open() { System.out.println("mouse open"); } }
/** *在USB接口处定义键盘 */ public class KeyByUSB implements USB { @Override public void close() { System.out.println("key close"); } @Override public void open() { System.out.println("key open"); } }
/** *最后就是定义配置文件,把配置文件放在项目主目录,命名为usb.properties,下面为配置文件的内容 */ usb1=MouseByUSB usb2=KeyByUSB
/** *Finally:当然是运行文件了 */ NoteBook book = new NoteBook(); book.run(); book.useUSB(null); //因为有了鼠标。所在需要在源程序中,创建鼠标对象并传到给笔记本。 //希望后期出现了设备以后,可不可以不用修改NoteBookMain的代码。还可以不断的加入新设备。
//对外提供配置文件,让程序不写死,给用户足够的USB使用定制权 File configFile = new File("usb.properties"); if(!configFile.exists()){ configFile.createNewFile(); } //读取流和配置文件关联。 FileInputStream fis = new FileInputStream(configFile);
//将流中的数据加载到prop。
Properties prop = new Properties();
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); }
//释放资源 fis.close();
补充知识点:用反射机制如何去获取类对象中的成员变量与成员方法
A、获取成员变量
String className = "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));
B、获取成员方法
//反射方法。非静态,有参数的show方法。 String className = "cn.itcast.domain.Person"; Class clazz = Class.forName(className); Method method = clazz.getMethod("paramShow", String.class,int.class); Object obj = clazz.newInstance(); method.invoke(obj, "xiaoqiang",40); //反射方法。静态,无参数的show方法。 String className = "cn.itcast.domain.Person"; Class clazz = Class.forName(className); Method method = clazz.getMethod("staticShow", null); method.invoke(null, null); //反射方法。非静态,无参数的show方法。 String className = "cn.itcast.domain.Person"; Class clazz = Class.forName(className); Method method = clazz.getMethod("show", null); Object obj = clazz.newInstance(); method.invoke(obj, null);
C、获取构造方法
String className = "cn.itcast.domain.Person"; Class clazz = Class.forName(className); /* * 万一给定类中没有空参数的呢? * 可以先获取指定的构造函数。在通过该构造函数进行实例化。 */ //1,通过Class获取指定构造函数。比如带两个参数。 Constructor cons = clazz.getConstructor(String.class,int.class); //2,通过指定的构造器对象进行对象的初始化。 Object obj = cons.newInstance("lisisi",23);