黑马程序员技术交流社区

标题: 关于代理返回的对象类型转换 [打印本页]

作者: Beautiful    时间: 2013-2-28 16:55
标题: 关于代理返回的对象类型转换
本帖最后由 戴俊毅 于 2013-3-1 08:43 编辑

在张老师的最后一课基础加强中实现类似spring的可配置的AOP框架的课程中,在AopFrameworkTest主函数中测试返回的是目标还是代理的时候,我们通过代理从配置文件config.properties中读取来通过代理创建了一个target  ArrayList的实例对象,但是通过这个代理的方法newProxyInstance()返回来一个指定接口的代理类实例,我们最多只能把这个反回来的对象转换为List,却不能转化为ArrayList。那现在我的问题是能不能通过代理返回是这个ArrayList的实例对象呢,而非接口实例呢,虽然我们讲究要面向接口编程,但是肯定会有那种时候我们不能面向接口编程的时候。所以或许代理就完成不了这个应用了。
  1. public class AopFrameworkTest {

  2.         /**
  3.          * @param args
  4.          */
  5.         public static void main(String[] args) throws Exception {
  6.                 // TODO Auto-generated method stub
  7.                 InputStream ips = AopFrameworkTest.class.getResourceAsStream("config.properties");
  8.                 Object bean = new BeanFactory(ips).getBean("xxx");
  9.                 System.out.println(bean.getClass().getName());
  10.                 ((Collection)bean).clear();
  11. ((List)bean).clear();
  12. ((ArrayList)bean).clear();//就这错了
  13. }

  14. }
复制代码

作者: 谢洋    时间: 2013-2-28 19:16
1、“通过代理创建了一个target  ArrayList的实例对象”
2、“那现在我的问题是能不能通过代理返回是这个ArrayList的实例对象呢,而非接口实例呢,”

我发现你上面两句话很有问题:第一句表明我们已经有了一个ArrayList 的实例target,
但第二句话你又说想通过代理返回另一个ArrayList的实例,这样子转了一圈,得到还是原来的东西。
就好比:你已经有了一台xxx电脑,然后你把你的xxx电脑交给代理商,然后又要代理商返回一台xxx电脑,是要换新的?
如果真的要这样子做,从代理的原理上是很不通的,但是可以返回一个和ArrayList实例功能完全相同的实例,惟一差别就是这个实例不是ArrayList类型的。
下面是张老师ppt上说的:
动态代理方式:
1、JVM生成的动态类必须实现一个或多个接口,所以,JVM生成的动态类只能用作相同接口的目标类的代理。
如果某类没有实现接口,那虚拟机就没办法了。
2、但用CgLIB库可以
CGLIB库可以动态生成一个类的子类,一个类的子类也可以用作该类的代理,
所以,如果要为一个没有实现接口的类生成动态代理,那么可以使用CGLIB库。
结论:
1、两种方式的共同点是:代理类其实都是目标类的父类的子类
   因为代理类是目标类的父类的子类,那么代理类除了与目标类有共同的基本方法外,
还可以添加自己特有的方法,而这些特有方法功能就是代理类的意义所在了,
如果不添加一些特有功能,那么这个代理类就完全没意义了,因为他跟目标类的功能是一模一样,分毫不差。
2,代理类在父类基础上添加的功能就在:newProxyInstance()方法中的参数(InvocationHandler的子类的invoke()方法中),到底是怎么实现的我也清楚。
3,上面说:(代理类其实都是目标类的父类的子类),并不是很准确,因为产生成出的代理实例的类的父类是Proxy,这里采用这个说法来表达,是为了更容易理解一些;
API的解释:Proxy 提供用于创建动态代理类和实例的静态方法,它还是由这些方法创建的所有动态代理类的超类。
另外,我认为动态代理的实现跟多态有一定的关系。


作者: Beautiful    时间: 2013-2-28 19:35
谢洋 发表于 2013-2-28 19:16
1、“通过代理创建了一个target  ArrayList的实例对象”
2、“那现在我的问题是能不能通过代理返回是这个Ar ...

你说的都对 嘿嘿我的意思可能没表达清楚,我的意思是假如我们刚好想去调用这个ArrayList的特有方法怎么办呢 比如clone()方法 ,这个时候我们该怎么去用这个代理类来调用这个方法呢?把代理类强制转换成ArrayList类不行啊。
作者: 谢洋    时间: 2013-2-28 20:47
戴俊毅 发表于 2013-2-28 19:35
你说的都对 嘿嘿我的意思可能没表达清楚,我的意思是假如我们刚好想去调用这个ArrayList的特有方法怎么办 ...

哦哦,这样表达就比较清楚了
你这样一问,我发现我上面的理解有很大的问题,先谢谢你的提问了:
1,我先说:"可以返回一个和ArrayList实例功能完全相同的实例",
然后接着说:
2,因为代理类是目标类的父类的子类,那么代理类除了与目标类有共同的基本方法外,
还可以添加自己特有的方法。
结论:都说功能完全相同(肯定包括ArrayList的所有功能),然后又说代理与ArrayList只共同的(没有特有的),打自已的嘴巴了?上面说法还可能有些问题,欢迎找茬!

知错必改!重新得出结论:代理类除拥有目标类的所有功能外,还拥有自己特有的功能。据于以下猜想:
假设,代理类只拥有目标类的共同方法(不包括特有的):从张老师的示例中来看,如果说newProxyInstance()方法仅仅是利用了目标类的接口,而没有从目标类中获取方法实体;但我们并没从重新复写这些接口的方法(接口的方法没有方法体,子类要执行必须复写),却可以在代理实例中直接使用这些方法;这足已表明这代理类的方法(除特有)是从目标类中copy过去的,然后再把这些方法与自已特有的方法一起组装成一个新的子类(代理类)。

作者: Beautiful    时间: 2013-3-1 08:42
谢洋 发表于 2013-2-28 20:47
哦哦,这样表达就比较清楚了
你这样一问,我发现我上面的理解有很大的问题,先谢谢你的提问了:
1,我先说 ...

哈哈有理,不过还是没解决,我已经想到解决办法了哈哈,反射。
作者: Beautiful    时间: 2013-3-1 08:50
哈哈谢谢张师兄给技术分




欢迎光临 黑马程序员技术交流社区 (http://bbs.itheima.com/) 黑马程序员IT技术论坛 X3.2