java动态代理详解
什么是代理
- 利用代理我们可以在运行时创建一个实现了一组给定接口的新类。
- 这种功能只有在编译时无法确定需要实现哪个接口时才有必要使用。
何时使用代理
- 代理类可以在运行时创建全新的类,这样的代理类能够实现指定的接口。
- 我们不能再运行时定义这些方法的新代码,而要提供一个调用处理器,即一个实现了InvocationHandler接口的类对象。
创建代理对象
无论何时用proxy调用某个方法,这个方法的名字和参数就会打印出来,之后再真正调用这个方法。class TraceHandler implements InvocationHandler{
private Object target;
public TraceHandler(Object t)
{
target = t;
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
System.out.print(target);
//print会自动调用toString方法
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);
}
}
Object invoke(Object obj, args)
调用包装在当前Method对象中的方法
obj:实例化后的对象。
args:用于方法调用的参数。
使用代理对象对二分法查找进行跟踪
static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler handler)
loader:类加载器,为null会使用默认的类加载器。
interfaces:
- interfaces数组中所有的对象必须表示接口,不能是类或者基本类型
- interfaces数组中不能有两个元素可以引用相同的类对象
handler:即我们刚刚实现了InvocationHandler接口的类
public class Main {
public static void main(String[] args) {
// write your code here
Object[] elements = new Object[1000];
for(int i = 0;i < elements.length;i++){
int value = i + 1;
InvocationHandler handler = new TraceHandler(value);
//每一个类都有一个隐含的静态成员class
Object proxy = Proxy.newProxyInstance(null,new Class[]{Comparable.class},handler);
elements[i] = proxy;
}
Integer key = new Random().nextInt(elements.length) + 1;
//binarySearch中调用了compareTo方法
int result = Arrays.binarySearch(elements,key);
if(result >= 0 ) System.out.println(elements[result]);
}
}
Integer类实现了Comparable接口,在binarySearch中会调用到Compara接口中的compareTo()方法。
为什么toString方法不属于Comparable接口也被代理——因为所有的代理类都覆盖了Object中的方法toString,equals和hashCode
- 所有的代理类都拓展与Proxy类
- 对于特定的类加载器和预设的一组接口来说,只能有一个代理类。
- 代理类一定是public或final
- 没有定义代理类的名字,JVM中的Proxy类将生成一个以字符串$Proxy开头的雷鸣
- 代理类是指在运行过程中创建的,一旦被创建就成为了常规类。
- 无论何时调用代理对象的方法,调用处理器(handler)的invoke方法都会被调用