这两天看完了《JAVA编程思想》第14章,对动态代理与反射机制有了初步的了解。
- 动态代理
概念:代理是基本的设计模式之一,它是你为了提供额外的或不同的操作而插入的用来代替“实际”对象的对象。这些操作通常涉及与“实际”对象的通信,因此代理通常充当中间人的角色。
在java的动态代理机制中,有两个重要的类或接口,一个是 InvocationHandler(Interface)、另一个则是 Proxy(Class),这一个类和接口是实现我们动态代理所必须用到的。
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。我们来看看InvocationHandler这个接口的唯一一个方法 invoke 方法:
Object invoke(Object proxy, Method method, Object[] args) throws Throwable proxy: 指代我们所代理的那个真实对象 method: 指代的是我们所要调用真实对象的某个方法的Method对象 args: 指代的是调用真实对象某个方法时接受的参数
接下来我们来看看Proxy这个类,Proxy这个类的作用就是用来动态创建一个代理对象的类,它提供了许多的方法,但是我们用的最多的就是 newProxyInstance 这个方法:
public static Object newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InvocationHandler h) throws IllegalArgumentException loader: 代理对象的类加载器(格式:代理对象.class.getClassLoader),不是很明白这个地方的类加载器最后是需要怎么写才是正确的,因为有些是些代理对象的类加载器,但是《JAVA编程思想》书本P345页代理SnowRemovalRobot.class对象时,写的类加载器是NullRobot.class(what fuck?) interfaces: 代理对象的接口列表,可以使用(格式:代理对象.getClass().getInterfaces()或者new Class[]{接口.class}))
h: 一个InvocationHandler对象,表示的是当我这个动态代理对象在调用方法的时候,会关联到哪一个InvocationHandler对象上
下面是一个Demo案例:
import java.lang.reflect.InvocationHandler; import java.lang.reflect.Method; import java.lang.reflect.Proxy; interface A{ void f(); void g(String name); } class B implements A{ @Override public void f() { // TODO Auto-generated method stub System.out.println("我是B的f"); } @Override public void g(String name) { // TODO Auto-generated method stub System.out.println("我是B的f"); } } class C implements A{ @Override public void f() { // TODO Auto-generated method stub System.out.println("我是C的f"); } @Override public void g(String name) { // TODO Auto-generated method stub System.out.println("我是C的g"); } } class ProxyDemo implements InvocationHandler{ //被代理的对象 private Object proxied; public ProxyDemo(Object proxied) { super(); this.proxied = proxied; } @Override public Object invoke(Object proxy, Method method, Object[] args) throws Throwable { // TODO Auto-generated method stub /* * 没有发现proxy具体有什么作用,这个指代的就是Proxy.newProxyInstance的第一个参数:类加载器 * 无论是A.class,B.class,还是demo.class 都不影响结果。 */ System.out.println("proxy:"+proxy.getClass()); //调用的接口方法 System.out.println("method:"+method+",args:"+args); //方法中参数列表 System.out.println("args:"+args); //调用被代理对象的调用方法,并传递参数 return method.invoke(proxied, args); } } public class Demo { public static void main(String[] args) { B b = new B(); //返回一个object的代理对象 Object newProxyInstance = Proxy.newProxyInstance(A.class.getClassLoader(), B.class.getInterfaces(), new ProxyDemo(b)); A a=(A)newProxyInstance; a.f(); a.g("wo"); C c = new C(); Object newProxyInstance2 = Proxy.newProxyInstance(Demo.class.getClassLoader(), C.class.getInterfaces(), new ProxyDemo(c)); A aa=(A)newProxyInstance2; aa.f(); aa.g("wo"); } }/*output: proxy:class priv.whh.edu.demo.$Proxy0 method:public abstract void priv.whh.edu.demo.A.f(),args:null args:null 我是B的f proxy:class priv.whh.edu.demo.$Proxy0 method:public abstract void priv.whh.edu.demo.A.g(java.lang.String),args:[Ljava.lang.Object;@7d67d940 args:[Ljava.lang.Object;@7d67d940 我是B的f proxy:class priv.whh.edu.demo.$Proxy0 method:public abstract void priv.whh.edu.demo.A.f(),args:null args:null 我是C的f proxy:class priv.whh.edu.demo.$Proxy0 method:public abstract void priv.whh.edu.demo.A.g(java.lang.String),args:[Ljava.lang.Object;@44fd13b5 args:[Ljava.lang.Object;@44fd13b5 我是C的g */
2. 反射机制
概念:Java 反射是 Java 被视为动态(或准动态)语言的一个关键性质。这个机制允许程序在运 行时透过 Reflection APIs 取得任何一个已知名称的class 的内部信息,包括其 modifiers( 诸如 public, static 等 )、superclass (例如 Object)、 实现之 interfaces(例如 Cloneable),也包括 fields 和 methods 的所有信息,并可于运行时改变 fields 内容或唤起 methods。Java 反射机制容许程序在运行时加载、探知、使用编译期间完全未知的 classes。 换言之,Java 可以加载一个运行时才得知名称的 class,获得其完整结构。
下面是一个Demo案例:
A.class:
public interface A{ void f(); void g(String name); }
B.class:
class B implements A{ @Override public void f() { // TODO Auto-generated method stub System.out.println("我是B的f"); } @Override public void g(String name) { // TODO Auto-generated method stub System.out.println("我是B的f"); } public void h() { System.out.println("我是B的h"); } public void hh(String name,Integer aa) { System.out.println("我是B的h"+name+aa); } }
HiddenC.class:
public class HiddenC { public static A makeA() { return new B(); } }Demo.class:
package priv.whh.edu.demo;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import priv.whh.edu.other.A;
import priv.whh.edu.other.HiddenC;
public class Demo {
/**
*
* @param a 反射的对象
* @param methodName 反射的方法
* @param args 反射的方法的参数列表
* @param parameterTypes 第一个参数类型
* @param parameterTypes2 第二个参数类型
* @param parameterTypes... 第n个参数类型
* @throws SecurityException
* @throws NoSuchMethodException
* @throws IllegalArgumentException
* @throws IllegalAccessException
* @throws InvocationTargetException
*/
static void callhiddneMethod(Object a,String methodName,Object[] args,Class<?> parameterTypes,Class<?> parameterTypes2) throws SecurityException, NoSuchMethodException, IllegalArgumentException, IllegalAccessException, InvocationTargetException{
Method declaredMethod = a.getClass().getDeclaredMethod(methodName,parameterTypes,parameterTypes2);
declaredMethod.setAccessible(true);
//使用了method.setAccessible(true)后 性能有了20倍的提升
//Accessable属性是继承自AccessibleObject 类. 功能是启用或禁用安全检查
declaredMethod.invoke(a,args);
}
public static void main(String[] args) throws SecurityException, IllegalArgumentException, NoSuchMethodException, IllegalAccessException, InvocationTargetException {
A a = HiddenC.makeA();
//a.f();
/*Compile Error B设置了默认访问权限,包之外无法访问 ,因此会编译错误
if(a instanceof B){
B b=(B)a;
b.h();
}
*/
//那不是要写无数个方法去调用不同类型的方法吗??? what fuck?
callhiddneMethod(a, "hh",new Object[]{"name",12},String.class,Integer.class);
}
}/*output:
我是B的hname12
*/