接上文,为什么JDK的动态代理需要依赖接口的实现呢?先来一段测试代码看看不依赖接口为报什么错。
Hello类不再实现sayHello接口:
package com.xiaosong.proxy.demo.service.impl;
public class Hello {
public void sayHello() {
// TODO Auto-generated method stub
System.out.println("Hello KuGou!");
}
}
测试类改为:
package com.xiaosong.proxy.demo.test;
import com.xiaosong.proxy.demo.jdkproxy.MyInvocationHandler;
import com.xiaosong.proxy.demo.service.impl.Hello;
public class TestProxy {
public static void main(String[] args) {
System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
//新建一个service实现类对象
// IHello hello = new Hello();
Hello hello = new Hello();
//传入服务实现类对象Hello、InvocationHandler对象(代理类的具体操作类) 来获取一个代理类实例
MyInvocationHandler my = new MyInvocationHandler(hello);
// IHello helloProxy = (IHello) my.getProxyObject();
Hello helloProxy = (Hello) my.getProxyObject();
helloProxy.sayHello();
}
}
运行结果如下:
Exception in thread "main" java.lang.ClassCastException: com.sun.proxy.$Proxy0 cannot be cast to com.xiaosong.proxy.demo.service.impl.Hello
at com.xiaosong.proxy.demo.test.TestProxy.main(TestProxy.java:18)
结果是$Proxy0 无法强制转换为Hello 类。那么$Proxy 是个什么东西呢?
代码中添加:System.getProperties().put("sun.misc.ProxyGenerator.saveGeneratedFiles","true");
并在项目根目录下创建:
,就会在运行期生成$Proxy 类了。进行反编译结果如下:
package com.sun.proxy;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy
{
private static Method m1;
private static Method m0;
private static Method m2;
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
static
{
try
{
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
}
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
可以看出$Proxy就是一个Proxy的子类,和Hello类没有任何关系,肯定无法强转。那么正常情况下的$Proxy 又是个什么东西呢?
package com.sun.proxy;
import com.xiaosong.proxy.demo.service.IHello;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.reflect.UndeclaredThrowableException;
public final class $Proxy0 extends Proxy implements IHello
{
//生成四个方法作为新代理类中的属性。包括hashcode,equals,tostring 和 接口实现方法。
private static Method m3;
private static Method m1;
private static Method m0;
private static Method m2;
//这个构造函数指向父类中Proxy中的构造函数,查看Proxy的对应构造函数是Protected修饰的,是只允许子类调用
public $Proxy0(InvocationHandler paramInvocationHandler)
throws
{
super(paramInvocationHandler);
}
//实现接口里的方法
public final void sayHello()
throws
{
try
{
//这里很关键,h 指的就是构造函数中的InvocationHandler类,这个类可以是看做是代理类的具体实现类。每次调用sayHello方法都会自动去调用代理类的具体实现类中的invoke方法。
this.h.invoke(this, m3, null);
return;
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final boolean equals(Object paramObject)
throws
{
try
{
return ((Boolean)this.h.invoke(this, m1, new Object[] { paramObject })).booleanValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final int hashCode()
throws
{
try
{
return ((Integer)this.h.invoke(this, m0, null)).intValue();
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
public final String toString()
throws
{
try
{
return (String)this.h.invoke(this, m2, null);
}
catch (RuntimeException localRuntimeException)
{
throw localRuntimeException;
}
catch (Throwable localThrowable)
{
}
throw new UndeclaredThrowableException(localThrowable);
}
static
{
try
{
m3 = Class.forName("com.xiaosong.proxy.demo.service.IHello").getMethod("sayHello", new Class[0]);
m1 = Class.forName("java.lang.Object").getMethod("equals", new Class[] { Class.forName("java.lang.Object") });
m0 = Class.forName("java.lang.Object").getMethod("hashCode", new Class[0]);
m2 = Class.forName("java.lang.Object").getMethod("toString", new Class[0]);
return;
}
catch (NoSuchMethodException localNoSuchMethodException)
{
throw new NoSuchMethodError(localNoSuchMethodException.getMessage());
}
catch (ClassNotFoundException localClassNotFoundException)
{
}
throw new NoClassDefFoundError(localClassNotFoundException.getMessage());
}
}
可以看出,不一样的是,这个$Proxy 是实现了IHello接口,自然是能够转成IHello对象了。继续阅读这个$Proxy类中内容,详见上面代码注释。可以看出这里代理类继承了Proxy类,对sayHello方法的调用是通过传入的接口的反射来实现的。所以jdk的动态代理是必须依赖接口的。