反射(reflection)学习整理_第1页
反射(reflection)学习整理_第2页
反射(reflection)学习整理_第3页
反射(reflection)学习整理_第4页
反射(reflection)学习整理_第5页
已阅读5页,还剩21页未读 继续免费阅读

下载本文档

版权说明:本文档由用户提供并上传,收益归属内容提供方,若内容存在侵权,请进行举报或认领

文档简介

1、-作者xxxx-日期xxxx反射(reflection)学习整理【精品文档】反射学习整理【摘要】本文主要通过自己对反射机制的总结编写的文档,主要目的就是为了自己以后能可以参考温习也可以方便刚刚入门的同仁们学习指导,通过doc的编写相信可以在帮助别人的同时提高自己。 反射机制; Reflection API; 如何使用反射机制; 反射机制的应用举例;第一节 反射机制什么是反射机制,说的通俗一些就是在java运行期间动态加载一些不确定的类对象,那么我们如何使用一个类的呢?当然大多数情况下我们是使用一个确定的类,然后通过在内存中的加载再使用之。其实在一个project中会有很多类,虚拟机并不是在每一

2、次运行时都将所有的类都进行加载然后解析的,是在我们使用的过程中才会被加载,这个大家可以看一下ClassLoader(在后期中我也会编写ClassLoader相关的文章总结)反射机制提供的功能: 加载运行时才能确定的数据类型; 解析类的结构,获取其内部的信息; 能够操作的类型或者实例;1. 访问属性;2. 调用方法;3. 创建新的对象;以上的功能我会在接下来的文字中都进行阐述,然后每一个功能点都会通过代码的形式进行逐一的说明举例;Java虚拟机在运行是能加载的类型有如下几种: 类接口; 数组; 枚举; 注解(Annotation,可以参见我的另一篇文档,java Annotation学习文档);

3、 基本数据类型;在类加载的时候,JVM会自动加载上述类型对应的Class对象。package com.wangwenjun.demo;import java.util.ArrayList;public class ReflectionDemo1 private final static String LIST_STRING=.ArrayList;SuppressWarnings(unchecked)public static void main(String args) try Class clazz=Class.forName(LIST_STRING);/通过反射获取运行时的Classnce

4、(); /通过newInstance方法获取Objectlist.add(hello);System.out.println(list.size()+:+list.get(0); catch (ClassNotFoundException e) e.printStackTrace(); catch (InstantiationException e) / TODO Auto-generated catch blocktStackTrace(); catch (IllegalAccessException e) / TODO Auto-generated catch blocke.printSt

5、ackTrace();执行结果为:1:hello通过上面的代码我们可以总结出来使用Reflection大致需要如下的几步: 获取目标对象的Class对象; 调用Class对象内省方法获取目标对类成员信息; 访问目标类的成员属性;通过第一步的操作,我们获取了目标对象的class之后就可以解析出来class对应的内部结构;别不多说直接上代码,来看看如何解析出来目标对象;我们定义一个Teacher类package com.wangwenjun.demo;public class Teacher private String username;private int age;private stati

6、c int total;public Teacher()super();total+;public Teacher(String username,int age)super();this.username = username;this.age = age;total+;public String getUsername() return username;public void setUsername(String username) this.username = username;public int getAge() return age;public void setAge(int

7、 age) this.age = age;public static int getTotal() return total;public static void setTotal(int total) Teacher.total = total;Overridepublic String toString()return UserName:+this.username+,age:+this.age;假如说上述的Teacher类是在我们运行时才知道的一个类,也就是说是我们运行时才能确定的一个类,那么我们就可以通过反射的形式将它解析出来,包括它的属性,方法,以及构造函数等等。好了,下面有一个专门

8、的类针对Teacher进行解析,通过观察打印的语句我们就可以看出来效果package com.wangwenjun.demo;import java.lang.reflect.Constructor;importlect.Field;import java.lang.reflect.Method;import java.lang.reflect.Modifier;public class ReflectionTeacher private final static String TEACHER_CLASS=com.wangwenjun.demo.Teacher;SuppressWarnings

9、(unchecked)public static void main(String args) try Class clazz = Class.forName(TEACHER_CLASS);Field fields = clazz.getDeclaredFields(); /获取该类中的属性成员Method methods = clazz.getDeclaredMethods();/获取该类中的成员方法Constructor constructors = clazz.getConstructors();/获取该类的所有构造方法System.out.println(*打印成员属性*);for(F

10、ield field:fields)System.out.println(属性:+field);System.out.println(名称:+field.getName();System.out.println(修饰符:+Modifier.toString(field.getModifiers();System.out.println(数据类型:+field.getType();System.out.println(=);System.out.println(*打印成员方法*);for(Method method:methods)System.out.println(方法:+method.to

11、String();System.out.println(方法名称:+method.getName();System.out.println(方法修饰符:+Modifier.toStrings();System.out.println(方法参数列表);Class mClass=method.getParameterTypes();System.out.print(mClass.length!=0?有参数:无参数:);for(Class c:mClass)System.out.print(c.getName()+类型t);System.out.println(n方法返回类型:+method.get

12、ReturnType().getName();System.out.println(=);System.out.println(*打印构造方法*);for(Constructor constructor:constructors)System.out.println(构造方法:+constructor.toString();System.out.println(构造方法名:+constructor.getName();System.out.println(构造方法修饰符:+Modifier.toString(constructor.getModifiers();Class mClass=con

13、structor.getParameterTypes();System.out.print(mClass.length!=0?有参数:无参数:);for(Class c:mClass)System.out.print(c.getName()+类型t);System.out.println(n=); catch (ClassNotFoundException e) e.printStackTrace();日志输出:*打印成员属性*名称:username修饰符:private=名称:age修饰符:private数据类型:int=名称:total修饰符:private static数据类型:int=

14、*打印成员方法*方法:public java.lang.String com.wangwenjun.demo.Teacher.getUsername()方法名称:getUsername方法修饰符:public方法参数列表无参数:=方法:public void com.wangwenjun.demo.Teacher.setUsername(java.lang.String)方法名称:setUsername方法修饰符:public方法参数列表有参数:java.lang.String类型方法返回类型:void=方法:public int com.wangwenjun.demo.Teacher.get

15、Age()方法名称:getAge方法修饰符:public方法参数列表无参数:方法返回类型:int=方法:public void com.wangwenjun.demo.Teacher.setAge(int)方法名称:setAge方法修饰符:public方法参数列表有参数:int类型方法返回类型:void=方法:public static void com.wangwenjun.demo.Teacher.setTotal(int)方法名称:setTotal方法修饰符:public static方法参数列表有参数:int类型方法返回类型:void=un.demo.Teacher.toString(

16、)方法名称:toString方法修饰符:public方法参数列表无参数:=方法:public static int com.wangwenjun.demo.Teacher.getTotal()方法名称:getTotal方法修饰符:public static方法参数列表无参数:方法返回类型:int=*打印构造方法*构造方法:public com.wangwenjun.demo.Teacher()构造方法修饰符:public无参数:=构造方法:public com.wangwenjun.demo.Teacher(java.lang.String,int)构造方法修饰符:public有参数:java

17、.lang.String类型int类型=通过观察日志我们可以发现,获取了属性,方法,构造函数,并且将它的属性名称,返回值类型等等全部都做了打印。通过对Teacher类的解析我们可以看出来反射机制的确非常的强大,它本身就非常强大,如果没有这种技术,像spring,ibatis,hibernate,struts等等基本上就实现不了或者说很难被实现。【补充】在解析的时候我们还可以将对象的父类以及父接口都得到,具体的说明暂时不做讲述,在后文中的Reflect API中就可以看得到。下面只是演示如何获取父类以及父接口Class superClass=clazz.getSuperclass();Syste

18、m.out.println(superClass.toString();Class superInterface = clazz.getInterfaces();for (int i = 0; i superInterface.length; i+) System.out.println(superInterfacei.toString();System.out.println(clazz.getPackage().toString();看完了如何动态加载一个类,如何解析类的结构,那么我们看看如何利用解析出来的结果对中的方法进行使用呢?需要说明的一点是在访问类的方法与属性之前呢必须先解析它,否

19、则我们是无法获得类中所包含的一切信息。为了能更加的清楚一些我们写一个简单的java对象,与文中的teacher类比较类似,但是相对teacher来说显得稍微简单一些。代码如下所示:package com.wangwenjun.demo;public class Student public String name;public static int count=100;public Student()super();public Student(String name)super(); = name;public void setValue(String name)this.

20、name = name;public void showCount()System.out.println(Student对象被实例化了+count+次);public String toString()return Name:++,调用次数:+count; 访问name属性的操作方法:package com.wangwenjun.demo;import java.lang.reflect.Field;public class ReflectionStudent public static void main(String args) throws ClassNotFound

21、Exception, SecurityException, NoSuchFieldException, IllegalArgumentException, IllegalAccessException Student s = new Student(zhangsan);Class clazz = s.getClass();Field f=clazz.getField(name);Object o=f.get(s);System.out.println(修改前:+f.getName()+的值:+o);f.set(s, 张三);o=f.get(s);System.out.println(修改后:+

22、f.getName()+的值:+o);打印语句:修改前:name的值:zhangsan修改后:name的值:张三 访问setValue方法的操作方法package com.wangwenjun.demo;importion;import java.lang.reflect.Method;public class ReflectionStudent public static void main(String args) throws ClassNotFoundException, SecurityException, NoSuchFieldException, IllegalArgumentE

23、xception, IllegalAccessException, NoSuchMethodException, InvocationTargetException Student s = new Student(zhangsan);Class clazz = s.getClass();Method m = clazz.getMethod(setValue, new ClassString.class);m.invoke(s, new Object张三);System.out.println(s.toString();执行结果后打印信息为:Name:张三,调用次数:101通过上述代码可以看出来

24、,name的值之前”zhangsan”,然后通过调用setValue方法将值更改为了”张三”; 访问类的有参构造方法在这里我演示了如何访问Student类的构造方法,无参的构造函数也一样,代码如下:package com.wangwenjun.demo;import ;import java.lang.reflect.InvocationTargetException;public class ReflectionStudent SuppressWarnings(unchecked)public static void main(String args) throws ClassNotFoun

25、dException, SecurityException, NoSuchMethodException, IllegalArgumentException, InstantiationException, IllegalAccessException, InvocationTargetExceptionClass clazz = Class.forName(com.wangwenjun.demo.Student);Constructor c=clazz.getConstructor(new ClassString.class);Student s=(Student) c.newInstanc

26、e(new Object劉德華);System.out.println(s-+s);执行结果为:s-Name:劉德華,调用次数:101第二节 Reflection API通过上文中的所有代码应该对Reflection API的使用了解了大部分了,Reflection中的API也没有太多的接口和类,学习者应该按个去测试也应该没有什么问题接口摘要AnnotatedElement表示目前正在此 VM 中运行的程序的一个已注释元素。GenericArrayTypeGenericArrayType 表示一种数组类型,其组件类型为参数化类型或类型变量。GenericDeclaration声明类型变量的所有

27、实体的公共接口。InvocationHandlerInvocationHandler 是代理实例的调用处理程序 实现的接口。Member成员是一种接口,反映有关单个成员(字段或方法)或构造方法的标识信息。ParameterizedTypeParameterizedType 表示参数化类型,如 Collection。TypeType 是 Java 编程语言中所有类型的公共高级接口。TypeVariableTypeVariable 是各种类型变量的公共高级接口。WildcardTypeWildcardType 表示一个通配符类型表达式,如 ?、? extends Number 或 ? super

28、Integer。 类摘要AccessibleObjectAccessibleObject 类是 Field、Method 和 Constructor 对象的基类。ArrayArray 类提供了动态创建和访问 Java 数组的方法。ConstructorConstructor 提供关于类的单个构造方法的信息以及对它的访问权限。FieldField 提供有关类或接口的单个字段的信息,以及对它的动态访问权限。MethodMethod 提供关于类或接口上单独某个方法(以及如何访问该方法)的信息。ModifierModifier 类提供了 static 方法和常量,对类和成员访问修饰符进行解码。Prox

29、yProxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。ReflectPermission反射操作的 Permission 类。 异常摘要InvocationTargetExceptionInvocationTargetException 是一种包装由调用方法或构造方法所抛出异常的经过检查的异常。MalformedParameterizedTypeException当反射方法遇到语义错误的参数化类型,而反射方法需要实例化该类型时,抛出该异常。UndeclaredThrowableException如果代理实例的调用处理程序的 invoke 方法抛出一个

30、经过检查的异常(不可分配给 RuntimeException 或 Error 的 Throwable),且该异常不可分配给该方法(在代理实例上调用该方法,并将其指派到调用处理程序)的 throws 子句中声明的任何异常类,则由代理实例上的方法调用抛出此异常。 错误摘要GenericSignatureFormatError当需要解释类型、方法或构造方法的一般签名信息的反射方法遇到语法错误的签名属性时,抛出该错误。上述的包结构是我从API中粘贴出来的,有时间的话可以逐一进行test case练习。第三节 如何使用反射机制截止到现在,上面已经演示了若干个关于使用反射机制的demo,阅读者应该对此有一

31、个比较笼统的认识,但是为了更加详尽的说明一下,还是做简单的整理说明: 首先,知道何时才会去使用反射;首先我们需要明确的一点是,为什么要去使用反射机制呢?使用反射机制的主要原因是,在运行时我们不能事先知道需要使用那一个类,所以就需要在运行时动态的加载,如果能事先知道的话,就没有必要使用反射机制,反射机制毕竟是一个耗时的操作。 其次,需要加载类;需要将动态使用的类加载进来。 再次,解析类;加载完毕之后需要对类进行解析; 最后,访问类;通过反射API进行类的成员信息的访问。第四节 通过反射机制访问数组为什么将反射机制访问数组作为一个单独的章节,是因为我感觉它比较重要并且感觉它稍微复杂一些。在clas

32、s中有一个方法getComponentType(),该方法的作用为:返回表示数组组件类型的 Class。如果此类不表示数组类,则此方法返回 null。4.1 动态生成数组比如说我们要动态生成一个string类型的数组,并且它的长度为5package com.wangwenjun.demo;import java.lang.reflect.Array;public class ArraysTestOne public static void main(String args) Class clazz = String.class;Object objArrays = Array.newInsta

33、nce(clazz, 5);for(int i=0;i5;i+)Array.set(objArrays, i, i+);for(int i=0;i5;i+)System.out.println(Array.get(objArrays, i);System.out.println(=);String strs = (String) objArrays;for(String s:strs)System.out.println(s);程序的执行结果为:01234=012344.2 动态扩展数组假设我们现在有一个String类型的数组,其长度为5,在使用的时候我们需要将其更改为10个长度,这个时侯我们

34、该如何去做呢,想想按照我们通常的办法,该需求简直是不可想象的,但是通过反射机制就可以完全办得到。package com.wangwenjun.demo;import java.lang.reflect.Array;public class ArraysTestOne SuppressWarnings(unchecked)public static void main(String args) String strs = new Stringa,b,c,d,e;System.out.println(修改之前長度為:+strs.length);for(String s:strs)System.ou

35、t.print(s+t);System.out.println();Class clazz = strs.getClass().getComponentType();Object objNew =Array.newInstance(clazz, strs.length*2);int length = (String)objNew).length;System.out.println(修改之后長度為:+length);for(int i=0;istrs.length;i+)Array.set(objNew, i, Array.get(strs, i);String objStrs = (Stri

36、ng)objNew;for(String s:objStrs)System.out.print(s+t);代码执行结果如下:修改之前長度為:5abcde修改之后長度為:10abcdenullnullnullnullnull第五节 动态代理Java中的反射机制API封装了动态代理相关的API,这样在我们使用的时候就会方便很多,要知道什么是动态代理,首先了解一下静态代理。5.1 静态代理为什么要使用代理呢?在我们要实现某个功能的时候可能会做其他一些不相干的事情,这些不相干的事情其实不用出现在我们的业务逻辑处理代码中,这样会给程序的业务逻辑带来一些较差的可读性,并且提高了维护的成本。所以我们往往喜欢

37、将比较纯粹的业务逻辑进行单独的设计,其他的事情交由其它的类来做。【需求】:现在需要计算一个两数相加的需求,我们往往会在加法运算之前打印参数的信息,并且在运算之后打印结果信息,以往我们大多都会这样做package com.wangwenjun.demo;public class ProxyTest public int add(int arg1,int arg2)System.out.println(被加数为:+arg1);System.out.println(加数为:+arg2);int result = arg1+arg2;System.out.println(运算结果为:+result);

38、return result;public static void main(String args) int result=new ProxyTest().add(3, 4);System.out.println(执行结果为:+result);通过以上的代码可以看出add方法其实就是做了一个加法的操作,但是呢有三条日志信息都将其进行了分割,相对add操作,日志与其是没有任何关系的,这样在该方法中又增加了三条无谓的代码,所以呢,我们就有了代理机制,下面看看什么叫做代理。【Subject】package com.wangwenjun.demo;public interface Subject pu

39、blic int add(int arg1,int arg2);【RealSubject】package com.wangwenjun.demo;public class RealSubject implements Subject public int add(int arg1, int arg2) return arg1+arg2;【Proxy】package com.wangwenjun.demo;public class Proxy implements Subjectprivate Subject obj = null;public Proxy(Subject obj)this.ob

40、j = obj;public int add(int arg1, int arg2) System.out.println(被加数为:+arg1);System.out.println(加数为:+arg2);return obj.add(arg1, arg2);【Test Case】package com.wangwenjun.demo;public class ProxyTest public static void main(String args) Subject s = new Proxy(new RealSubject();int result=s.add(3, 4);System.

41、out.println(计算结果为:+result);通过上面的设计我们可以看得出来,负责计算加法运算的方法只是做了加法运算,并未做其他的事情,这样显得业务逻辑很纯粹。5.2 动态代理静态代理解决了业务逻辑与日志信息脱耦的一种设计,但是又带来其他的问题,也就是说我们有100个目标对象,就需要设计100个代理,这样会引起类爆炸(类非常多)。所以我们需要解决这样的问题,不过sun的jdkAPI给我们提供了现成的解决方案,那就是动态代理,通过我的代码演示,希望能够了解什么是动态代理,实现动态代理必须继承一个接口,这个借口就是InvocationHandler,该接口有一个方法,必须进行实现Objec

42、t invoke(Objectproxy,Methodmethod,Objectargs) throws Throwable现在开始使用动态代理package com.wangwenjun.demo;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import java.lang.reflect.Proxy;public class DynamicProxy implements InvocationHandlerprivate Object obj = null;public Object

43、bind(Object obj )this.obj = obj;return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj.getClass().getInterfaces(), this);public Object invoke(Object proxy, Method method, Object args)throws Throwable Object result = null;for(Object o:args)System.out.println(o);result = method.invoke(obj,

44、 args);return result;测试代码如下:package com.wangwenjun.demo;public class ProxyTest public static void main(String args) DynamicProxy d =new DynamicProxy();Subject proxy=(Subject) d.bind(new RealSubject();int result=proxy.add(3, 4);System.out.println(执行结果为:+result);打印信息:34执行结果为:7更为详细的关于proxy模式的文章请关注我后期有关

45、24中设计模式的总结。第六节 反射机制的应用举例为了能让读者更加清晰的了解到反射机制到底能够做什么,到底能够给我们在以后的软件开发中带来多大的方便,接下来我会以两个完整的实际示例进行详细的示范与解析。6.1 Struts消息接受Struts有一个很方便的操作就是我们通过它的标签就可以完成属性值的收集过程,如果熟悉struts的人应该知道,只要我们在页面中配置了与javabean一一对应的属性名字,在后台的处理过程中我们会将传递过来的值得到,当然这些都是由struts框架为我们实现的,接下来我们就模拟这样的场景进行一下属性值的收集操作。假定我们有一个登陆页面,其中需要填写userName,pas

46、sWord这样两个值,当然在该文中不会真的去做这样的页面,我们会将假定的输入保存在一个properties中去,我们定义属性值所在的javabean为userBean,代码如下:package com.wangwenjun.demo;import java.lang.reflect.InvocationTargetException;import java.lang.reflect.Method;import java.util.Enumeration;import java.util.Hashtable;import java.util.Properties;public class Use

47、rLoginAction private static Hashtable session=new Hashtable();private static Properties props = new Properties();/存放用户的登录信息staticprops.put(userName, zhangsan);props.put(passWord, admin);SuppressWarnings(unchecked)public static void main(String args) Enumeration propNames= pertyNames();while

48、(propNames.hasMoreElements()String propName = (String) propNames.nextElement();String propValue = props.getProperty(propName);collect(propName,propValue);UserBean userBean=session.get(user);System.out.println(userBean.getUserName();System.out.println(userBean.getPassWord();private static void collec

49、t(String propertyName,String propertyValue)UserBean userBean = session.get(user);Class userClass = null;Object obj = null;try if(null=userBean)userClass = Class.forName(com.wangwenjun.demo.UserBean);obj = userClass.newInstance();elseobj = userBean;userClass = userBean.getClass();String temp1 = propertyNam

温馨提示

  • 1. 本站所有资源如无特殊说明,都需要本地电脑安装OFFICE2007和PDF阅读器。图纸软件为CAD,CAXA,PROE,UG,SolidWorks等.压缩文件请下载最新的WinRAR软件解压。
  • 2. 本站的文档不包含任何第三方提供的附件图纸等,如果需要附件,请联系上传者。文件的所有权益归上传用户所有。
  • 3. 本站RAR压缩包中若带图纸,网页内容里面会有图纸预览,若没有图纸预览就没有图纸。
  • 4. 未经权益所有人同意不得将文件中的内容挪作商业或盈利用途。
  • 5. 人人文库网仅提供信息存储空间,仅对用户上传内容的表现方式做保护处理,对用户上传分享的文档内容本身不做任何修改或编辑,并不能对任何下载内容负责。
  • 6. 下载文件中如有侵权或不适当内容,请与我们联系,我们立即纠正。
  • 7. 本站不保证下载资源的准确性、安全性和完整性, 同时也不承担用户因使用这些下载资源对自己和他人造成任何形式的伤害或损失。

评论

0/150

提交评论