JAVA之类加载机制与反射(三)

使用反射生成JDK动态代理


在Java的java.lang.reflect包下提供了一个Proxy类和一个InvocationHandler接口,通过使用这个类和接口可以生成JDK动态代理类或动态代理对象。

使用Proxy和InvocationHandler创建动态代理


Proxy提供了用于创建动态代理类和代理对象的静态方法,它也是所有动态代理类的父类。如果在程序中为一个或多个接口动态地生成实现类,就可以使用Proxy来创建动态代理类;如果需要为一个或多个接口动态地创建实例,也可以使用Proxy来创建动态实例

系统生成的每一个代理对象都有一个与之相关的InvocationHandler对象。

package 使用反射生成JDK动态代理;

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

interface Person
{
	void walk();
	void sayHello(String name);
}
class MyInvocationHandler implements InvocationHandler
{
	public Object invoke(Object proxy,Method method,Object []args)
	{
		System.out.println("-----正在执行的方法: "+method);
		{
			if(args!=null)
			{
				System.out.println("下面是执行该方法时传入的实参为: ");
				for(Object val:args)
				{
					System.out.println(val);
				}
			}
			else
			{
				System.out.println("该方法没有实参");
			}
		}
		return null;
	}
	}
public class ProxyTest {
	public static void main(String []args) throws Exception
	{
		InvocationHandler handler=new MyInvocationHandler();
		Person p=(Person)Proxy.newProxyInstance(Person.class.getClassLoader(), new Class[]{Person.class}, handler);
		p.walk();
		p.sayHello("小明");
	}
}

运行结果为:
JAVA之类加载机制与反射(三)_第1张图片

可以很明显地看出,不管程序执行代理对象的的walk()方法还是sayHello()方法,实际上都是在执行InvocationHandler和invoke()方法

在普通编程过程中,确实无须使用动态代理,但在编写框架或底层基础代码时,动态代理的作用就非常大。


动态代理和AOP

在某些方法的前后可能要使用某些通用处理,我们固然可以直接将代码考进去,或者写成函数在里面调用,但是这会导致高耦合性。而AOP可以通过动态代理来解决这个问题
Dog.java
package 使用反射生成JDK动态代理;

public interface Dog {
	void info();
	void run();
}
GunDog.java
package 使用反射生成JDK动态代理;


public class GunDog implements Dog {
	@Override
	public void info() {
		
		System.out.println("我是猎狗");

	}
	@Override
	public void run() {
		System.out.println("猎狗在奔跑");

	}

}
DogUtil.java
package 使用反射生成JDK动态代理;

public class DogUtil {
	public void method1()
	{
		System.out.println("======模拟第一个通用方法========");
	}
	public void method2()
	{
		System.out.println("======模拟第二个通用方法======");
	}

}
MyInvokationHandler.java
package 使用反射生成JDK动态代理;

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

public class MyInvokationHandler implements InvocationHandler{
	private Object target;
	 void setTarget(Object target)
	{
		this.target=target;	
	}
	
	@Override
	public Object invoke(Object proxy,Method method,Object []args) throws Exception
	{
		DogUtil du=new DogUtil();
		du.method1();
		Object result=method.invoke(target, args);
		du.method2();
		return result;
	}

	
}
MyProxyFactory.java
package 使用反射生成JDK动态代理;

import java.lang.reflect.Proxy;

public class MyProxyFactory {
	public static Object getProxy(Object target)throws Exception
	{
		MyInvokationHandler handler=new MyInvokationHandler();
		handler.setTarget(target);
		return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(),handler );
	}

}

Test.java
package 使用反射生成JDK动态代理;
i
public class Test {
	public static void main(String []args)throws Exception
	{
		Dog target=new GunDog();
		Dog dog=(Dog)MyProxyFactory.getProxy(target);
		dog.info();
		dog.run();
	}
}
运行结果为:
JAVA之类加载机制与反射(三)_第2张图片


使用动态代理可以非常灵活地实现解耦。使用Proxy生产一个动态代理时,往往并不会凭空产生一个动态代理,这样没有实际意义。往往是根据指定的目标对象生成动态代理

这种动态代理在AOP(Aspect Orient Programming,面向切面编程)中被称为AOP代理,AOP代理可替代目标对象,AOP代理包含了目标对象的全部方法。
不过AOP代理可以在执行目标方法之前、之后插入一些通用代理。


反射和泛型

通过在反射中使用泛型,可以避免使用反射生成的对象需要强制类型转换

泛型和Class类

正常的Class cls=Class.forName(claName)需要使用强制类型转换(因为返回的类型是Class的实例,无法直接使用)
但是,通过泛型就可以很简单地避免这个问题

package 反射和泛型;

import java.util.Date;

import javax.swing.JFrame;

public class CrazyitObjectFactory {
public static T getInstance(Class cls)
{
	try
	{
		return cls.newInstance();
	}
	catch(Exception e)
	{
		e.printStackTrace();
		return null;
	}
	}
public static void main(String []args)
{
	Date d=CrazyitObjectFactory.getInstance(Date.class);
	JFrame jf=CrazyitObjectFactory.getInstance(JFrame.class);
	System.out.println("运行成功");
}
}
输出结果为:

可以看到,当使用以上方法来产生对象时,无需进行强制类型转换,系统会执行更为严格的检查,不会出现ClassCastException异常。


当使用Array.newInstance()方法时,返回的是一个Object对象——这个设置导致用户需要强制类型转换,而强制类型转换是不安全的操作
通过对该方法进行包装,可以有效利用泛型的优势

package 反射和泛型;

import java.lang.reflect.Array;

public class CrazyitArray {
public static  T[] newInstance(Class componentType,int length)
{
	return (T[])Array.newInstance(componentType, length);
}
public static void main(String []args)
{
	String []arr=CrazyitArray.newInstance(String.class, 10);
	int [][]intarr=CrazyitArray.newInstance(int [].class, 6);
	arr[6]="hello";
	intarr[1]=new int[]{33,55,66};
	System.out.println(arr[6]);
	System.out.println(intarr[1][1]);
}
}
运行结果为:

通过将方法签名改为public static T[] newInstance(Class componentType ,int length)可以保证返回值是数组对象,而不是Object对象,从而避免了强制了类型转换


通过反射来获取泛型信息

通过制定类对应的Class对象,就可以获得该类里包含的所有成员变量,不管该成员变量是使用private修饰还是使用public修饰。获得了成员变量对应的Field对象后,就可以很容易的获得该成员变量的数据类型。

Class a=f.getType();

但这种方式只对普通类型的成员变量有效,如果该成员变量的类型是有泛型的类型(如HashSet类型),则不能准确返回泛型类型

所以,应使用如下方法:
package 反射和泛型;

import java.lang.reflect.Field;
import java.lang.reflect.ParameterizedType;
import java.lang.reflect.Type;
import java.util.Map;

public class GenericTest {
	private Map score;
	public static void main(String []args)throws Exception
	{
		Class clazz=GenericTest.class;
		Field f=clazz.getDeclaredField("score");
		Class a=f.getType();
		System.out.println(a);
		Type gType=f.getGenericType();
		if(gType instanceof ParameterizedType)
		{
			ParameterizedType p=(ParameterizedType)gType;
			Type rType=p.getRawType();
			System.out.println("原始类型为"+rType);
			Type []Targs=p.getActualTypeArguments();
			System.out.println("实际泛型信息为");
			for(int i=0;i

输出结果为:
JAVA之类加载机制与反射(三)_第3张图片




Type gType=f.getGenericType();
ParameterizedType p=(ParameterizedType)gType;
Type rType=p.getRawType();
Type []Targs=p.getActualTypeArguments();

就是实现流程


Type也是java.lang.reflect包下的一个接口,该接口代表所有类型的公告高级接口,Class是Type接口的实现类。Type包括原始类型、参数化类型、数组类型、类型变量和基本类型




你可能感兴趣的:(JAVA入门)