反射
2016-04-29 19:13
211 查看
java中有一个Class类型,该类型的变量用于描述一个类或接口的结构信息,如通过Class类型的变量,可以获取其描述的类的名字,全部方法,属性…。
java中的任何一个类型都能 . 出静态变量class,如类.class,接口.class,int.class,boolean.class。
对于基本数据类型的类包装,不仅可以 . 出class,还可以 . 出TYPE,如Integer.TYPE,TYPE是一个Class类型的静态常量,Integer.class指的是Integer引用类型,Integer.TYPE指的是int基本类型。
反射的本质就是通过,该类型的Class类型变量,来获取其描述的类型的各种信息,而后再做出相应的操作。
这一步完成的任务是,通过类的完全限定名,利用Class类的静态方法加载类到JVM,并返回已加载类的Class类型的变量。
这种方式不需要import该类,但是工程目录下,或是classpath指定的路径下必须有该类,否则JVM找不到。
通过c,可以获取加载的类Student的相关信息。
前面通过forName方法加载了类,并通过c获取到了加载的类的各种信息,现在要想使用这些信息,必须要先实例化一个该类的实例,然后才可以使用。
方法参数的Class类型变量数组,注意一个类或接口的Class类型变量只有一个,Class类型变量就是对应这个类,这个类的所有对象都是共享这个类的Class类型的变量。
A a = new A(); //接口同样具有此特性 Class c = a.getClass() = A.class
java中的任何一个类型都能 . 出静态变量class,如类.class,接口.class,int.class,boolean.class。
对于基本数据类型的类包装,不仅可以 . 出class,还可以 . 出TYPE,如Integer.TYPE,TYPE是一个Class类型的静态常量,Integer.class指的是Integer引用类型,Integer.TYPE指的是int基本类型。
//c可以描述任何一个引用类型的结构,?必须是引用类型。 Class<?> c //c仅可以描述T类型的结构,T是泛型,实际指代何种类型,在程序运行后确定 Class<T> c //c仅可以描述Student类型的结构 Class<Student> c //c可以描述Student类型及其该类型的子类类型的结构 Class<? extends Student> c
反射的本质就是通过,该类型的Class类型变量,来获取其描述的类型的各种信息,而后再做出相应的操作。
Class<Stident> c = Class.forName(“com.lnu.reflect.Student”);
这一步完成的任务是,通过类的完全限定名,利用Class类的静态方法加载类到JVM,并返回已加载类的Class类型的变量。
这种方式不需要import该类,但是工程目录下,或是classpath指定的路径下必须有该类,否则JVM找不到。
通过c,可以获取加载的类Student的相关信息。
//获取类Student的全部访问修饰符为public的属性 Field[] fields = c.getFields(); //获取类Student的已经声明的全部属性 Field[] fields = c.getDeclaredFields(); //获取属性fields[i]的访问修饰符编码,返回的是int型的编码 int code = fields[i].getModifiers(); //返回编码对应的访问修饰符 Modifier.toString(code); //返回属性fields[i]的类型的类类型变量 Class<?> field_class = field[i].getType(); //返回属性fields[i]的名字 String name = fields[i].getName(); //获取类Student的全部访问修饰符为public的方法 Method[] methods = c.getMethods(); //获取类Student的已经声明的全部方法 Method[] methods = c.getDeclaredMethods(); //返回方法的访问修饰符,名字同上 //返回方法的返回类型的类类型变量使用getReturnType() //返回方法的全部参数的类型的类类型变量 getParameterTypes()
前面通过forName方法加载了类,并通过c获取到了加载的类的各种信息,现在要想使用这些信息,必须要先实例化一个该类的实例,然后才可以使用。
Object obj = c.newInstance(); Class<?> params_classes = {参数1的Class类型变量,参数2的Class类型变量...};
方法参数的Class类型变量数组,注意一个类或接口的Class类型变量只有一个,Class类型变量就是对应这个类,这个类的所有对象都是共享这个类的Class类型的变量。
//根据方法的名字和方法的参数的类型的Class类型变量的数组获取方法 Method method = c.getDeclaredMethod(“方法的名字”, params); //方法的参数变量值数组 Object[] params_values = {参数1,参数2,…}; //设置方法的执行权限,使其可以执行私有方法 method.setAccessible(true); //执行方法,需要给出执行方法的类的实例和方法的参数变量值数组 method.invoke(obj, params_values); //根据属性的名字返回指定的属性 Field field = c.getDeclaredField(“属性名”); //设置属性的访问权限,使其可以访问私有属性 field.setAccessible(true); //获取类的实例obj的属性field的值 field.get(obj); //设置类的实例obj的属性field的值为value field.set(obj, value); public class ReflectTest { public static void main(String[] args) { Class<?> c = null; try { //加载类,要用类的完全限定名,返回加载类的Class类型的变量 c = Class.forName("com.lnu.reflect.example.Student"); //获取类的公共属性信息,getDeclaredFields()是获取全部属性 System.out.println("=====获取类的公共属性信息====="); Field[] public_properties = c.getFields(); for(int i = 0; i < public_properties.length; i++) { System.out.println("属性访问修饰符:" + Modifier.toString(public_properties[i] .getModifiers())); System.out.println("属性类型的类类型变量:" + public_properties[i].getType()); System.out.println("属性名:" + public_properties[i].getName()); System.out.println(); } //获取此类的公共方法信息,这包括子类继承的公共方法 System.out.println("=====获取类的公共方法信息====="); Method[] public_methoda = c.getMethods(); for(int i = 0; i < public_methoda.length; i++) { System.out.println("方法访问修饰符:" + Modifier.toString(public_methoda[i] .getModifiers())); System.out.println("方法返回值类型的类类型变量:" + public_methoda[i].getReturnType()); System.out.println("方法名:" + public_methoda[i].getName()); //返回方法参数的类型的类类型变量 for(int j = 0; j < public_methoda[i] .getParameterTypes().length; j++) { System.out.println("方法的参数" + (int)(j + 1) + "的类型的类类型变量:%s" + (public_methoda[i] .getParameterTypes())[j]); } System.out.println(); } //获取此类的全部方法信息,不包括此类继承的方法 //输出的方法顺序未必就是类中定义的方法的顺序 //由此调用方法时,必须知道方法的名字 System.out.println("=====获取类的全部方法信息====="); Method[] all_methoda = c.getDeclaredMethods(); for(int i = 0; i < all_methoda.length; i++) { //操作同上 } System.out.println("=====执行类的某个方法====="); //实例化此类的一个对象,看newInstance()方法的源代码可以发现,方法 //定义的返回类型是T,即是一个泛型,只有在实际用时才会知道T代表什么类 型,在此我们创建Class的变量c所指代的类型的一个实例 Object obj = c.newInstance(); //创建此方法的参数的类型的类类型变量数组 Class<?>[] param_types = {String.class, Integer.TYPE}; //根据方法的名字和方法参数的类型的类类型变量数组获取方法 Method method = c.getDeclaredMethod("say_4", param_types); //创建执行方法的参数变量值数组 Object[] param_values = {"test", 1}; //设置方法的执行权限,使其可以执行私有的方法 method.setAccessible(true); //调用此方法,参数为方法所属的对象以及执行方法所需要的参数值数组 String return_result = (String)method .invoke(obj, param_values); System.out.println("方法的返回值:" + return_result); System.out.println("==返回类的某个属性值,并重新赋值=="); Field field = c.getDeclaredField("message"); field.setAccessible(true); String field_value = (String)field.get(obj); System.out.println("属性message的值:" + field_value); field.set(obj, "I am a student"); String field_value_modified = (String)field.get(obj); System.out.println("重新赋值后的属性message的值:" + field_value_modified); } catch (Exception e) { System.out.println("ReflectionTest " + e.toString()); } } }
相关文章推荐
- 冲刺第十天
- 1.项目大致架构设计
- android.view.WindowManager$BadTokenException: Unable to add window — token null
- Scrum 团队成立 -- 软件工程
- hdu-1285拓扑排序
- 冲刺7
- MAC卸载/删除 Parallels Desktop虚拟机的方法
- 【7】Zabbix WEB指标监控
- Java 内部类的一些总结
- 实验十一 路由器综合路由配置
- 无线网卡工作模式笔记
- 解决安装pycrypto时的错误:Unable to find vcvarsall.bat
- 欢迎使用CSDN-markdown编辑器
- 虚拟机VirtualBox安装遇见问题
- 下标运算符[]重载
- iOS开发多线程篇—线程的状态
- vSphere Client 更改 ESX/ESXi 主机的端口
- 阿里巴巴集团CRO刘振飞:双11的六维技术准备
- web.xml 中以编码方式添加filter并设置初始化参数
- ssh及sshfs