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这个接口的作用。
这个接口中只需要重写一个
这个方法。需要实际指定的是proxy这个对象。
你将Object proxy = new ArrayList();
Object retVal = method.invoke(proxy, args);
return retVal;
指定之后,这个动态代理就会有血有肉。
事实上,其实整个过程就是做了一个Collection colection = new ArrayList();这样一个简单的操作。
如果哪里没有说明白,你哪里不明白,还可以继续留言,我继续给你回复。{:3_57:}
|