黑马程序员技术交流社区

标题: 创建动态类的实例对象为什么是Collection类型的? [打印本页]

作者: 过犹不及    时间: 2014-7-3 17:18
标题: 创建动态类的实例对象为什么是Collection类型的?
就是这句话Collection proxy=(Collection)constructor.newInstance(new MyInvocationHandler());为什么是Collection。可能答案很简单,但我就是想不通,请各位大仙指点一下
作者: 李小然    时间: 2014-7-3 18:14
1.为什么是Collection?
    回答这个问题,你要明白proxy是由constructor实例化出来的。
    那么就要明白constructor是哪里来的。
    Constructor constructor = clazz.getConstructor(InvocationHandler.class);
    这话的意思是constructor是从clazz这个字节码文件中得到参数是InvocationHandler的构造函数。(动态代理的构造函数参数都是InvocationHandler)
    就要明白clazz是什么。
    Class clazz = getProxyClass(Collection.class.getClassLoader(), Collection.class);
    这句话的意思是,创造一个动态代理字节码,需要实现Collection.class这个字节码的接口。你就明白了,原来问题是在这里。是这个字节码文件导致实例化出来对象是Collection的。

2.为什么要强转?使用(Collection)
   这涉及到编译器的问题,他只可以解决编译阶段的问题。运行阶段的问题他是看不到的。
   你在clazz中参数是Collection.class,你明白你在创造一个动态字节码文件,实现Collection接口。
   但是编译器不明白,因为你可以随意更改这个字节码文件(保证是个接口),编译器不会那么智能的判断出实例化出来的是什么东西。
   所以返回的是一个Object对象,他可以接受任意你选择的字节码接口文件。
   所以如果你不强转,一个父类引用是不可以指向子类的。会出现错误。

3.即便你这样写了,其实真正意义上来讲,这个动态代理对象没有真正实现Collection的所有功能。
   他只有形,而没有魂。类似于写一个网页文件你只做了前台,后台的功能还没添加。
   这就需要了解InvocationHandler这个接口的作用。
   这个接口中只需要重写一个
[size=-1]Object
invoke(Object proxy, Method method, Object[] args)
   这个方法。需要实际指定的是proxy这个对象。
   你将Object proxy = new ArrayList();
           Object retVal = method.invoke(proxy, args);
           return retVal;
    指定之后,这个动态代理就会有血有肉。
    事实上,其实整个过程就是做了一个Collection colection = new ArrayList();这样一个简单的操作。


如果哪里没有说明白,你哪里不明白,还可以继续留言,我继续给你回复。{:3_57:}





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