代理类可以在运行时创建全新的类,这样的代理类能够实现指定的接口,尤其是他具有下列方法
1.指定接口所需要的全部方法
2.object类中的全部方法比如tostring,equals等
所有的代理类都覆盖了object类中的tostring,equals和hashcode,如果代理对象被调用这些方法,那么也是会被重新定向到调用处理器里面的invoke方法中的。
如果使用同一个类加载器和接口数组调用两次newProxyInstance方法的话,那么只能够得到同一个类的两个对象,也可以利用getProxyClass方法获得这个类, class proxyClass = Proxy.getProxyClass(null,interfaces[]);
代理类一定是public和final,如果代理类实现所有的接口都是public,代理类就不属于某个特定的包,否则所有非公有的接口都必须属于同一个包,同事代理类也属于这个包。可以通过是有那个Proxy类中的isProxyClass方法检测一个特定的CLASS对象是否是一个代理类。
如果一个类的某一方法我们需要修改其行为, 如数据库连接池中Connection.close()方法, 并不是真正的去关闭连接, 而只是把这个连接放入连接池里, 所以我们需要拦截这个方法的原来行为, 更改为只是放入连接池. 可以简单的继承java.sql.Connection, 然后实现所有方法, 但只更改close()的行为. 这样做很容易理解, 但是如果一个类的方法太多, 做起来工作量可能会很大.
import java.util .*;
import java.lang.reflect.*;
public class Test01 {
public static void main(String[] args) {
MyInvocationHandler mih = new MyInvocationHandler();
MyClass mc = new MyClass();
// 当调用mi的方法时, 如果是要特殊处理的就特殊处理, 否则就调用他对应的那个对象(mc)的方法.
MyInterface mi = mih.bind(mc);
mi.fight();
System.out .println(mi.toString());
}
}
interface MyInterface {
void fight();
}
class MyClass implements MyInterface {
public void fight() {
System.out .println("Orz, fighting....." );
}
@Override
public String toString() {
return "Hello";
}
}
class MyInvocationHandler implements InvocationHandler {
MyClass mc ;
MyInterface mi ;
public MyInterface bind(MyClass mc) {
this .mc = mc;
this .mi = (MyInterface) Proxy.newProxyInstance (MyInterface.class
.getClassLoader(), new Class[] { MyInterface.class }, this );
return mi ;
}
public Object invoke(Object proxy, Method method, Object[] args)
throws Throwable {
// 当调用mi(即proxy)的方法时, 如果是要特殊处理的就特殊处理, 否则就调用他对应的那个对象(mc)的方法.
if ("fight" .equals(method.getName())) {
System.out .println("XXXXXXXXXXXXXXXX" );
return null ;
} else {
return method.invoke(mc , args);
}
}
}