java反射和动态代理

  • 格式:doc
  • 大小:71.50 KB
  • 文档页数:6

JAVA反射和动态代理 参考网址:http://developer.51cto.com/developer/javabook/images/10.pdf 在Java运行时环境中,对于任意的一个类,能否知道这个类的所有属性和方法?对于任意一个对象,能否调用它的任意一个方法?答案是肯定的。这种动态获得类的信息,以及动态调用对象的方法的功能来自于java语言的反射机制。Java的反射机制提供了以下功能: 1.在运行时获得任意对象所属的类; 2.在运行时构造任意一个类的对象; 3.在运行时得到任意一个对象的所有方法和属性; 4.在运行是动态的调用一个对象的任意方法; 5.生成动态代理。 一、反射API简介 在JDK中,主要由下面的类来完成java的反射机制,这些类都是在java.lang.reflect 包下: Class:代表一个类,这是一个核心类,包含了对某个具体类的所有信息的描 述; Field:代表类的成员变量(即属性); Method:代表类的成员方法; Constructor:代表类的构造方法; Array:提供了动态创建数组,以及访问数组元素的静态方法。 DumpMethods 类演示了Reflection API的基本作用,它读取命令行参数指定的类名,然 后打印这个类所具有的方法信息: import java.lang.reflect.*; class DumpMethods { public static void main(String[] args) throws Exception{ Class cl = Class.forName(args[0]); Method[] methods = cl.getDeclaredMethods();

for(int i = 0; i < methods.length; i ++){ System.out.println(methods[i].toString()); } } } 示ReflectTester 类进一步演示了Reflection API 的基本使用方法。ReflectTester 类有一个copy(Object object)方法,这个方法能够创建一个和参数object同样类型的 对象,然后把object对象中的所有属性复制到新建的对象中,并将它返回。 这个例子只能复制简单的JavaBean,假定JavaBean的每个属性都有public类型的 getXXX()和setXXX()方法。 import java.lang.reflect.*; public class ReflcetTest{ public static Object copyObj(Object obj) throws Exception{ //获得obj的类 Class cl = obj.getClass(); //通过默认的构造函数构造实例对象 Object copyObj = cl.getConstructor(new Class[]{}).newInstance(new Object[]{}); //得到声明的属性 Field[] fields = cl.getDeclaredFields(); for(int i = 0; i < fields.length; i ++){ Field field = fields[i]; String fieldName = field.getName(); //得到属性名的第一个字母的大些形式 String firstLetter = fieldName.substring(0,1).toUpperCase();

String getMethodName = "get" + firstLetter + fieldName.substring(1); String setMethodName = "set" + firstLetter + fieldName.substring(1); //得到相应的get,set方法 Method setMethod = cl.getMethod(setMethodName,new Class[]{field.getType()}); Method getMethod = cl.getMethod(getMethodName,new Class[]{}); //得到原有对象的此属性的值 Object value = getMethod.invoke(obj,new Object[]{}); //将原有值设置到新对象中 setMethod.invoke(copyObj,new Object[]{value}); } return copyObj; }

public static void main(String[] args) throws Exception{ Student s = new Student(); s.setName("luoxiaoyi"); s.setSex("male"); Student s1 = (Student)ReflcetTest.copyObj(s); System.out.println(s1.getName() + " " + s1.getSex()); } } class Student{ private String name ; private String sex; public Student(){} public void setName(String name){ this.name = name; } public void setSex(String sex){ this.sex = sex; } public String getName(){ return this.name; } public String getSex(){ return this.sex; } } java.lang.Array 类提供了动态创建和访问数组元素的各种静态方法。ArrayTester1 类的 main()方法创建了一个长度为20 的字符串数组,接着把索引位置为5 的元素设为 “luoxiaoyi”,然后再读取索引位置为5 的元素的值。 import java.lang.reflect.*; public class ArrayTester1{ public static void main(String[] args)throws Exception{ Class cl = Class.forName("java.lang.String"); Object arrayObj = Array.newInstance(cl,20); Array.set(arrayObj,4,"luoxiaoyi"); String name = (String)Array.get(arrayObj,4); System.out.println(name); } } ArrayTester2 类的main()方法创建了一个5×10×15 的整型数 组,并把索引位置为[3][5][10]的元素的值为设37。 import java.lang.reflect.*; public class ArrayTester2{ public static void main(String args[]) { int dims[] = new int[]{5, 10, 15}; Object array = Array.newInstance(Integer.TYPE, dims); //使arrayObj 引用array[3] Object arrayObj = Array.get(array, 3); Class cls = arrayObj.getClass().getComponentType(); System.out.println(cls); //使arrayObj 引用array[3][5] arrayObj = Array.get(arrayObj, 5); //把元素array[3][5][10]设为37 Array.setInt(arrayObj, 10, 37); int arrayCast[][][] = (int[][][]) array; System.out.println(arrayCast[3][5][10]); } } 二、在远程方法调用中运用反射机制 1、假定在SimpleServer 服务器端创建了一个HelloServiceImpl对象,它具有getTime() 和print()方法。HelloServiceImpl类实现了HelloService接口。如src\reflect\remote 下HelloService接口和HelloServiceImpl类的源程序。 2、SimpleClient客户端如何调用服务器端的HelloServiceImpl对象的getTime()和echo()方 法呢?显然,SimpleClient客户端需要把调用的方法名、方法参数类型、方法参数值, 以及方法所属的类名或接口名发送给SimpleServer,SimpleServer 再调用相关对象的方 法,然后把方法的返回值发送给SimpleClient。为了便于按照面向对象的方式来处理客 户端与服务器端的通信,可以把它们发送的信息用Call 类(src\reflect\remote)来 表示。一个Call对象表示客户端发起的一个远程调用,它包括调用的类名或接口名、方 法名、方法参数类型、方法参数值和方法执行结果。 3、SimpleClient 调用SimpleServer 端的HelloServiceImpl 对象的print()方法的流程如下。 (1)SimpleClient 创建一个Call 对象,它包含了调用HelloService 接口的print()方法 的信息。 (2)SimpleClient通过对象输出流把Call对象发送给SimpleServer。 (3)SimpleServer 通过对象输入流读取Call 对象,运用反射机制调用 HelloServiceImpl 对象的echo()方法,把echo()方法的执行结果保存到Call对象中。 (4)SimpleServer 通过对象输出流把包含了方法执行结果的Call 对象发送给 SimpleClient。 (5)SimpleClient通过对象输入流读取Call对象,从中获得方法执行结果。如 src\reflect\remote的SimpleServer 和SimpleClient 的源程序。 三、静态代理 四、动态代理:(例子程序:src\reflect\proxy) 与静态动态代理相比,动态代理类的字节码在程序运行时由java反射机制自动生成, 不需要程序员自行编写。动态代理不仅简化了程序的编码工作,而且提高了软件系统的 可扩展性,因为,java反射机制能生成任意类型的动态代理类。Java.lang.reflect 包下的Proxy类和InvocationHandler接口提供了生成动态代理类的能力; Proxy类提供了创建动态代理类和动态代理类实例对象的静态方法: 1、getProxyClass()创建动态代理类,完整定义如下: public static Class getProxyClass(ClassLoader loader, Class[]interfaces); loader: 被代理类的类装载器; interfaces: 被代理类所实现的所有接口。 2、newProxyInstance()创建动态代理类的实例对象,完整定义如下: public static Object newProxyInstance(Classloader loader, Class[] interfaces,InvocationHandler handler); loader: 被代理类的类装载器; interfaces: 被代理类所实现的所有接口, handler: 指定与动态代理类关联的InvocationHandler对象。