java反射技术:
* JAVA反射机制是在运行状态中,对于任意一个类(class),都能够知道这个类的所有属性和方法
* 对于任意一个对象,都能调用他的任意一个方法和属性
* 这种动态获取的信息以及动态调用对象的方法功能成为java语言的反射机制
*
*
* 动态获取类中信息,就是反射机制
* 可以理解为对类的解剖
*
* 要相对字节码进行解剖,必须要哟字节码文件对象
获取字节码的三种方法:<strong> </strong>/* * 第一种获取字节码的方法 * */ public static void getClassObject_1() { Person p = new Person(); Class clazz = p.getClass(); Person p1 = new Person(); Class clazz1 = p1.getClass(); System.out.println(clazz1==clazz); } /* * 第二种 *任何数据类型都具备一个静态属性,class获取对应的class对象 *相对简单,但是还是要明确用到类中的静态成员,不够扩展 * */ public static void getClassObject_2() { Class clazz = Person.class; Class clazz1 = Person.class; System.out.println(clazz==clazz1); } /* * 第三种 * 只要通过给定的类的字符串名称就可以获取该类,更为扩展 * 可以通过Class类中的方法来完成 * forName(); * 这种方式只要有名称即可,扩展性更强 * */ public static void getClassObject_3() throws Exception { String className = "FanShe.Person"; //类名必须要加包名,就算导包了也要加 Class clazz = Class.forName(className); }
反射的用法:
1、需要获得java类的各个组成部分,首先需要获得类的Class对象,获得Class对象的三种方式:
Class.forName(classname) 用于做类加载
obj.getClass() 用于获得对象的类型
类名.class 用于获得指定的类型,传参用
2、反射类的成员方法:
Class clazz =Person.class;
Method method =clazz.getMethod(methodName, new Class[]{paramClazz1, paramClazz2});
method.invoke();
3、反射类的构造函数:
Constructor con =clazz.getConstructor(new Class[]{paramClazz1, paramClazz2,...})
con.newInstance(params...)
4、反射类的属性:
Field field =clazz.getField(fieldName);
field.setAccessible(true);
field.setObject(value);
获取了字节码文件对象后,最终都需要创建指定类的对象,创建对象的两种方式(其实就是对象在进行实例化时的初始化方式):
1、调用空参数的构造函数:使用了Class类中的newInstance()方法。
2、调用带参数的构造函数:先要获取指定参数列表的构造函数对象,然后通过该构造函数的对象的newInstance(实际参数) 进行对象的初始化。
public static void getClassObject_3() throws Exception { String className = "FanShe.Person"; //类名必须要加包名,就算导包了也要加 Class clazz = Class.forName(className); //第一种方法: Object obj = clazz.newInstance(); //创建一个新实例,此方法只创建空参数 //第二种方法: /* * 当获取指定名称对应类中的所体现的对象时,而该对象初始化不使用空参数构造时该怎么办呢? * 既然是通过指定的构造函数进行对象的初始化,所以应该先获取到该构造函数 * * */ Constructor constructor = clazz.getConstructor(String.class,int.class); Object object = constructor.newInstance("小明",25); }
综上所述,第二种方式,必须要先明确具体的构造函数的参数类型,不便于扩展。所以一般情况下,被反射的类,内部通常都会提供一个公有的空参数的构造函数。
利用反射获取字段:
<strong> </strong>public static void getField()throws Exception { String className = "cn.itheima.Person"; Class clazz = Class.forName(className); Constructor constructor = clazz.getConstructor(String.class,int.class); Person p = (Person)constructor.newInstance("张三",22); //获取字段,只获取公共 Field field = clazz.getField("name"); //获取本类字段,包括私有 Field field1 = clazz.getDeclaredField("age"); //对字段取消权限检查 field1.setAccessible(true); //设置获取字段 field1.set(p,25); System.out.println(field1.get(p)); field.set(p, "李四"); String name = (String)field.get(p); System.out.println(name); }
利用反射获取方法:
<strong> </strong>public static void getMethod()throws Exception { String className = "cn.itheima.Person"; Class clazz = Class.forName(className); Person p = (Person)clazz.getConstructor(String.class,int.class).newInstance("李四",88); //获取所有公共方法 Method[] methods = clazz.getMethods(); //获取本类方法,包含私有 //Method[] methods = clazz.getDeclaredMethods(); System.out.println(methods.length); for(Method m : methods) { System.out.println(m.toString()); } //获取某个方法 Method method = clazz.getMethod("getName",null); Method method1 = clazz.getMethod("show",String.class,int.class); //调用方法 System.out.println(method.invoke(p)); System.out.println(method.invoke(p,"xiaoming",22)); }
使用反射注意两点:1、如果用反射调用的是静态方法,则调用invoke方法时,不用写对象,如果此方法有参数,则对象写null;
2、如果要调用的函数是一个数组,java会把它拆包成若干个对象,这时,要将这个对象封装成一个对象如:(Object)new String[];
反射扩展练习:
/* 一台电脑有一块主板,主板有一个接口,电脑运行主板 有一个声卡实现了这个主板接口,在电脑运行 后期又添加了一个网卡,让网卡业运行起来,利用反射技术,不修改任何代码的情况下, 修改配置文件就可以直接让网卡跑起来 */ package cn.itheima; import java.util.*; import java.lang.reflect.*; import java.net.*; import java.io.*; public class ReflectDemo { /** * @param args */ public static void main(String[] args)throws Exception { Properties pro = new Properties(); FileInputStream fis = new FileInputStream("PCI.properties"); //将流中的键值对加载进集合 pro.load(fis); for(int x=0;x<pro.size();x++) { String className = pro.getProperty("PCI"+(x+1)); //在获取字节码文件的时候要确定字节码文件要导包 System.out.println(className); Class clazz = Class.forName(className); //父类的引用指向了子类对象,子类实现了父类的方法,所以使用的还是子类的实现方法 //后期添加了网卡,那么这个网卡实现了主板接口,拿到这个实现的类名,创建此对象 Mainboard p =(Mainboard)clazz.newInstance(); //调用主板接口中的方法,也就是子类实现父类的方法 p.opend(); p.close(); } //getField(); //getMethod(); } public class SoundCord implements Mainboard { public void opend() { System.out.println("SoundCord--声卡运行"); } public void close() { System.out.println("SoundCord--声卡关闭"); } } package cn.ittest; public class NetCord implements Mainboard { public void opend() { System.out.println("NetCord--网卡运行"); } public void close() { System.out.println("NetCord--网卡关闭"); } } public interface Mainboard { void opend(); void close(); }
java高新技术:反射
最新推荐文章于 2022-12-21 23:11:07 发布