关于java的反射机制及动态代理

java反射技术早都听说了,之前只是了解反射提供的方法,可是不知道反射技术到底该怎么使用,或者说什么时候能用到反射技术,最近看jvm有了一些新的感悟。


首先,反射概念是什么?

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射。

什么是动态获取呢?就是直到运行时还可以修改自身状态或行为,相对于编译后就不可改变来说,是动态的,那么是如何获取的呢?前面学类加载的时候,会根据字节码在内存中生成一个代表这个类的对象,就是说根据字节码,我们可以得到这个对象的属性方法构造函数等信息,注意,用newInstance()方法时,是重新生成新的对象,并不是将原来对象还原。并且可以动态的进行修改,这也就是一些框架为什么根据配置文件可以动态的进行填充。反射实际上破坏了对象的封装性。

动态代理:根据接口信息动态生成代理对象,其实也是根据字节码生成的,相当于不用提前写好代理类,运行时才生成(实际上是加载的过程中吧),这也就是动态的由来吧。

下面看一个例子吧:

package com.zk.reflect;

import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;

public class DynamicProxyTest
{
    interface Subject
    {
    	void sayHello();
    }
    static class RealSubject implements Subject
    {

		@Override
		public void sayHello()
		{
			System.out.println("say hello");
			
		}
    	
    }
    /**
     * 动态代理:代理类是运行时动态生成的,是根据RealSubject的字节码生成的实例,会生成和RealSubject
     * 实现相同接口的实例,如果有100个RealSubject,静态代理的话也要有100个代理对象,要写100个代理对象的代码,而动态代理只会写
     * 这一个生成动态代理类的代码,优势不光是这个,可以实现在原始类和接口未知的情况下,确定代理类的代理行为。
     * 
     * @param args
     */
    public static void main(String[] args)
	{
		Subject su=(Subject)new DynamicProxy().bind(new RealSubject());
		su.sayHello();
	}
}
class DynamicProxy implements InvocationHandler
{

	private Object oriObj;
	public Object bind(Object obj)
	{
		this.oriObj=obj;
		
		return 
		Proxy.newProxyInstance(oriObj.getClass().getClassLoader(), oriObj.getClass().getInterfaces(),
				this);
	}
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable
	{
		System.out.println("before");
		 method.invoke(oriObj, args);
		System.out.println("after");
		return null;
	}
	
}
每一个动态代理类都必须要实现InvocationHandler这个接口,并且每个代理类的实例都关联到了一个handler,当我们通过代理对象调用一个方法的时候,这个方法的调用就会被转发为由InvocationHandler这个接口的 invoke 方法来进行调用。invoke里面实际上调用的是真实对象的方法。


那么代理对象的类型是什么呢?

为什么我们可以 通过

Subject su=(Subject)new DynamicProxy().bind(new RealSubject());这样的方式强制转换。


可能我以为返回的这个代理对象会是Subject类型的对象,或者是InvocationHandler的对象,结果却不是,首先我们解释一下为什么我们这里可以将其转化为Subject类型的对象?原因就是在newProxyInstance这个方法的第二个参数上,我们给这个代理对象提供了一组什么接口,那么我这个代理对象就会实现了这组接口,这个时候我们当然可以将这个代理对象强制类型转化为这组接口中的任意一个,因为这里的接口是Subject类型,所以就可以将其转化为Subject类型了

同时我们一定要记住,通过 Proxy.newProxyInstance 创建的代理对象是在jvm运行时动态生成的一个对象,它并不是我们的InvocationHandler类型,也不是我们定义的那组接口的类型,而是在运行是动态生成的一个对象,并且命名方式都是这样的形式,以$开头,proxy为中,最后一个数字表示对象的标号

 
  

当我通过代理对象来调用方法的时候,起实际就是委托由其关联到的 handler 对象的invoke方法中来调用,并不是自己来真实调用,而是通过代理的方式来调用的。

你可能感兴趣的:(java)