使用代理 Proxzy 可以在运行时创建一组给定接口的新类,这种功能只有在编译时无法确定需要实现哪种接口时才需要使用。
假如有一个表示接口的 Class 对象,它的确切类型在编译时无法得知。由于没有实现类而只有一个接口,反射和newInstance
语句是无法实例化这个 Class 对象的,我们需要在程序处于运行状态时定义一个新类。
代理类可以在运行时创建全新的类,这样的代理类可以实现指定的接口,它具有下列方法:
toString()
、equals()
等。在代理机制中,不能再允许时定义这些方法的新代码,而是要提供一个调用处理器 InvocationHandler,调用处理器是实现了InvocationHandler
接口的类对象。在这个接口中只有一个方法:
Object invoke(Object proxy, Method method, Object[] args)
无论何时调用代理对象的方法,invoke()
方法都被调用,并向其传递 Method 对象和原始的调用参数,调用处理器必须给出处理调用的方式。
创建代理对象要使用 Proxy 类的newProxyInstance
方法,这个方法有三个参数:
下面给出一个示例程序,使用代理和调用处理跟踪方法调用:
// 调用处理器 class TraceHandler implements InvocationHandler{ private Object target; // 构造函数 public TraceHandler(Object t){ target = t; } // invoke方法 public Object invoke(Objcet proxy, Method m, Object[] args) throws Throwable { // print method name and parameters ... // invoke actual method return m.invoke(target, args); } }
下面的代码,我们用于跟踪方法调用的代理对象:
Object value = ...; // 构造调用处理器 InvocationHandler handler = new TraceHandler(value); // 构造代理对象 Class[] interfaces = new Class[](Comparable.class); Object proxy = Proxy.newProxyInstance(null, interfaces, handler);
我们再用 proxy 任何方法时,都会调用invoke()
方法,打印出方法的名字和参数,再用value
对象调用它。
代理类有下面这样一些特性:
TraceHandler
中包装了实际的对象target
。toString()
、equals()
、hashCode()
。如果所有的代理方法一样,这些方法仅仅调用了调用处理器的invoke()
。Object 类中的其他方法没有被重新定义。newProxyInstance()
方法,那么只能得到一个类的两个对象。isProxyClass()
方法检测一个特定的 Class 对象是否是一个代理类。