Java 动态代理与反射机制

     这两天看完了《JAVA编程思想》第14章,对动态代理与反射机制有了初步的了解。

  1. 动态代理

     概念:代理是基本的设计模式之一,它是你为了提供额外的或不同的操作而插入的用来代替“实际”对象的对象。这些操作通常涉及与“实际”对象的通信,因此代理通常充当中间人的角色。  

     在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
*/


猜你喜欢

转载自blog.csdn.net/qq_32589355/article/details/80178179
今日推荐