利用代理可以在运行时创建一个实现了一组给定接口的新类。
6.5.1何时使用代理
假设由一个表示接口的Class对象(可能只包含一个接口),它的确切类型在编译时无法知道。要想构造一个实现这些接口的类,就需要使用newInstance方法或反射找出这个类的构造器。但是不能实例化一个接口,需要在程序处于运行状态时定义一个新类。
代理类可以在运行时创建全新的类。
调用处理器,是实现了InvocationHandler接口的类对象。
6.5.2创建代理对象
要想创建一个代理对象,需要使用Proxy类的newProxyInstance方法。这个方法有三个参数:
- 类加载器;
- 一个Class对象数组,每个元素都是需要实现的接口。
- 一个调用处理器。
为什么使用代理?
- 路由对远程服务器方法的调用。
- 在程序运行期间,将用户事件与动作关联起来。
- 调试,跟踪方法用。
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; import java.util.Arrays; import java.util.Random; public class ProxyTest { public static void main(String[] args) { Object [] elments = new Object[10]; for (int i = 0; i < elments.length; i++) { Integer value = i + 1; InvocationHandler invocationHandler = new TraceHandler(value); Object proxy = Proxy.newProxyInstance(null,new Class[]{Comparable.class}, invocationHandler); elments[i] = proxy; } Integer key = new Random().nextInt(elments.length) + 1; int result = Arrays.binarySearch(elments,key); System.out.println("result " + result); if (result >= 0) System.out.println(elments[result]); } } class TraceHandler implements InvocationHandler{ private Object target; public TraceHandler(Object o){ target = o; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { System.out.print(target); System.out.print("." + method.getName() + "("); if(args != null){ for (int i = 0; i < args.length; i++) { System.out.print(args[i]); if(i < args.length -1) System.out.print(", "); } } System.out.println(")"); return method.invoke(target,args); } }
println方法调用代理对象的toString。
6.5.3代理的特性
代理类是在运行过程中创建的。而一旦创建就变成了常规类,与虚拟机中的其它类没区别。
所有的代理类都扩展与Proxy类。一个代理类只有一个实例域–调用处理器,它定义在Proxy的超类中。未来履行代理对象的职责,所需要的任何附加数据都必须存储在调用处理器。如TraceHandler。
使用getProxyClass方法获得这个类。
Class proxyClass = Proxy.getProxyClass(null,interfaces)
代理类一定是public final的。
//是否是一个代理类 Proxy.gisProxyClass(Class<?> c1)