反射

1.Java 反射:

Reflection(反射)是被视为动态语言的关键,反射机制允许程序在执行期借助于Reflection API取得任何类的内部信息,并能直接操作任意对象的内部属性及方法

2.Java 反射的作用:

1)在运行时判断任意一个对象所属的类
2)在运行时构造任意一个类的对象
3)在运行时判断任意一个类所具有的成员变量和方法
4)在运行时调用任意一个对象的成员变量和方法
5)生成动态代理

3.反射的API

java.lang.Class:代表一个类
java.lang.reflect.Method:代表类的方法
java.lang.reflect.Field:代表类的成员变量
java.lang.reflect.Constructor:代表类的构造方法

实例:

import java.io.File;
import java.lang.reflect.Field;
import java.lang.reflect.Method;

import org.junit.Test;

public class TestReflection {

	@Test
	public void testClass() throws Exception{
		Class<Person> clazz = Person.class;
		
		/**
		 * 创建对象
		 */
		//1.创建运行时类Person的对象:newInstance()
		Person person = clazz.newInstance();
		
		/**
		 * 属性操作
		 */
		//1.获取public属性名:getFields()
		Field[] fields = clazz.getFields();
		for(int i = 0;i < fields.length;i++){
			System.out.println("###" + fields[i].getName());
		}
		//2.获取全部属性名:getDeclaredFields()
		Field[] fields1 = clazz.getDeclaredFields();
		for(int i = 0;i < fields1.length;i++){
			System.out.println("!!!" + fields1[i].getName());
		}
		
		//3.获取public属性:getField(String fieldname)
		Field field = clazz.getField("name");
		//通过set方法,为对应的类的对应属性赋值
		field.set(person, "LiuDeHua");
		System.out.println("name : " + person.getName());
		
		//4.获取非public属性:getgetDeclaredField(String fieldName)
		Field field2 = clazz.getDeclaredField("age");
		//通过setAccessible方法,改变private属性的封装性
		field2.setAccessible(true);
		field2.set(person, 40);
		System.out.println("age : " + person.getAge());
		
		/**
		 * 方法操作
		 */
		//1.获取运行时类方法的名称:getDeclatedMethods()  getMethods()
		Method[] methods = clazz.getDeclaredMethods();
		for(int i = 0;i < methods.length;i++){
			System.out.println("@@@" + methods[i].getName());
		}
		
		//2.获取运行时类指定的方法:getMethod(String methodName,Class...paramtype)
		Method method = clazz.getMethod("show");
		method.invoke(person);
		
		Method method2 = clazz.getMethod("display",String.class,int.class);
		method2.invoke(person, "xiaoming",10);
	}
}

4.java.lang.Class:是反射的源头

1)public final Class getClass():在Object类中定义了该的方法,此方法将被所有子类继承。该方法返回值的类型是一个Class类,此类是Java反射的源头,实际上所谓反射从程序的运行结果来看也很好理解,即:可以通过对象反射求出类的名称

2)生成Class实例之后,我们可以进行的操作

(1)创建对应运行时类对象

(2)获取对应运行时类的完整结构(属性、方法、构造器,父类,所在的包,注解,异常等等)

(3)调用对应的运行时类指定的结构(属性,方法,构造器)

(4)反射的应用:动态代理

3)如何获取Class实例(3种)

	/**
	 * 获取Class实例方法
	 * @throws Exception
	 */
	@Test
	public void testGetClassInstance() throws Exception{
		//1.调用运行时类本身的.class属性
		Class clazz = Person.class;
		System.out.println(clazz.getName());
		
		//2.通过运行时类的对象获取
		Person person = new Person();
		Class clazz1 = person.getClass();
		System.out.println(clazz1.getName());
		
		//3.通过Class静态方法forName(String classpath)
		Class clazz2 = Class.forName("reflection.Person");
		System.out.println(clazz2.getName());
		
		//4.通过类的加载器:
		ClassLoader classLoader = this.getClass().getClassLoader();
		Class clazz3 = classLoader.loadClass("reflection.Person");
		System.out.println(clazz3.getName());
	}

4)Class类的常用方法


5)ClassLoader

	/**
	 * ClassLoader获取输入流
	 * @throws Exception 
	 */
	@Test
	public void testClassLoeader() throws Exception{
		ClassLoader classLoader = this.getClass().getClassLoader();
		//通过getResourceStream(String filepath)可以得到一个输入流
		InputStream inputStream = classLoader.getResourceAsStream("classloader.txt");
		FileOutputStream fos = new FileOutputStream("classloader1.txt");
		byte[] b = new byte[10];
		int len;
		while((len = inputStream.read(b)) != -1){
			fos.write(b,0,len);
		}
	}
5.创建类对象:调用Class对象的newInstance()方法       要  求:1)类必须有一个无参数的构造器。2)类的构造器的访问权限需要足够。

	/**
	 * 创建运行时类对象,使用newInstance(),实际上就是调用了运行时类的空参构造器
	 * 要求:1)对应的运行时类要有空参构造器
	 *      2)构造器的权限要足够
	 * @throws Exception 
	 */
	@Test
	public void testNewInstance() throws Exception{
		String className = "reflection.Person";
		Class clazz = Class.forName(className);
		Person person = (Person)clazz.newInstance();
		System.out.println(person);
	}
6.通过反射调用类的完整结构

1)获取属性

	/**
	 * 获取属性相关信息
	 * @throws SecurityException 
	 * @throws Exception 
	 */
	@Test
	public void testGetFieldInfo() throws Exception{<span style="background-color: rgb(255, 153, 0);">
</span>		Class clazz = Person.class;
		
		//1.获取public属性名:getFields()
		Field[] fields = clazz.getFields();

		//2.获取全部属性名:getDeclaredFields()
		Field[] fields1 = clazz.getDeclaredFields();
		
		//3.获取public属性:getField(String fieldname)
		Field field = clazz.getField("name");
		
		//4.获取非public属性:getgetDeclaredField(String fieldName)
		Field field2 = clazz.getDeclaredField("age");
		
		//5.获取属性的权限符  变量类型  变量名称
		for(Field f : fields1){
			//1)权限符 
			int i = f.getModifiers();
			String name = Modifier.toString(i);
			System.out.println(name);
			//2)变量类型
			Class type = f.getType();
			System.out.println(type.getName());
			//3)变量名称
			String methodName = f.getName();
			System.out.println(methodName);
		}
	}
2)获取方法

	/**
	 * 获取方法相关属性
	 * @throws SecurityException 
	 * @throws Exception 
	 */
	@Test
	public void testGetMethodInfo() throws Exception{
		Class clazz = Person.class;
		
		//1.getMethods():返回运行时类及其父类中所有public的方法
		Method[] methods = clazz.getMethods();
		for(Method m : methods){
			System.err.println(m);
		}
		
		//getDeclatedMethods():返回运行时类自己本身声明的所有方法
		Method[] methods2 = clazz.getDeclaredMethods();
		for(Method m : methods2){
			System.out.println(m);
		}
		
		//2.获取运行时类指定的方法:getMethod(String methodName,Class...paramtype)
		Method method = clazz.getMethod("show");
		Method method2 = clazz.getMethod("display",String.class,int.class);
	}
3)获取父类泛型

	/**
	 * 获取父类的泛型:JDBC中会用到
	 * @throws SecurityException 
	 * @throws Exception 
	 */
	@Test
	public void testGenericType() throws Exception{
		Class clazzClass = Person.class;
		Type type = clazzClass.getGenericSuperclass();
		ParameterizedType paraType = (ParameterizedType)type;
		Type[] types = paraType.getActualTypeArguments();
		for(Type t : types){
			System.out.println(((Class)t).getName());
		}
	}

7.通过反射调用类中指定方法和属性

1)调用指定属性

public Field getField(String name) 返回此Class对象表示的类或接口的指定的public的Field。

public Field getDeclaredField(String name)返回此Class对象表示的类或接口的指定的Field。

public Object get(Object obj) 取得指定对象obj上此Field的属性内容

public void set(Object obj,Object value) 设置指定对象obj上此Field的属性

public void setAccessible(true)访问私有属性时,让这个属性可见

	/**
	 * 调用指定属性 
	 */
	@Test
	public void test() throws Exception{
		Class clazz = Person.class;
		//1.创建Person对象
		Person person = (Person)clazz.newInstance();
		//2.为public属性赋值并获取
		Field field = clazz.getField("name");
		field.set(person, "xiaoming");
		field.get(person);
		System.out.println(field.get(person));
		//3.为非public属性赋值并获取
		Field field2 = clazz.getDeclaredField("age");
		field2.setAccessible(true);
		field2.set(person, 10);
		field2.get(person);
		System.out.println(field2.get(person));
	}	
2)调用指定方法

通过Class类的getMethod(String name,Class…parameterTypes)方法取得一个Method对象,并设置此方法操作时所需要的参数类型。

之后使用Object invoke(Object obj, Object[] args)进行调用,并向方法中传递要设置的obj对象的参数信息。

	/**
	 * 调用指定方法 
	 */
	@Test
	public void test2() throws Exception{
		Class clazz = Person.class;
		Person person = (Person)clazz.newInstance();
		
		Method method = clazz.getMethod("show");
		Object returnVal = method.invoke(person);
		System.out.println("show's returnVal : " + returnVal);
		
		Method method2 = clazz.getMethod("toString");
		Object returnVal2 = method2.invoke(person);
		System.out.println("toString's returnVal : " + returnVal2);
		
		Method method3 = clazz.getMethod("display", String.class,int.class);
		Object returnVal3 = method3.invoke(person, "xiaohong",10);
		System.out.println("display's returnVal : " + returnVal3);
	}
8.动态代理
1)动态代理是指客户通过代理类来调用其它对象的方法,并且是在程序运行时根据需要动态创建目标类的代理对象。

2)代理设计模式的原理:使用一个代理将对象包装起来, 然后用该代理对象取代原始对象. 任何对原始对象的调用都要通过代理. 代理对象决定是否以及何时将方法调用转到原始对象上

3)代理类的作用:

(1)授权机制: 不同级别的用户对同一对象拥有不同的访问权利,如Jive论坛系统中,就使用Proxy进行授权机制控制,访问论坛有两种人:注册用户和游客(未注册用户),Jive中就通过类似ForumProxy这样的代理来控制这两种用户对论坛的访问权限.

(2)某个客户端不能直接操作到某个对象,但又必须和那个对象有所互动。举例两个具体情况:如果那个对象是一个是很大的图片,需要花费很长时间才能显示出来,那么当这个图片包含在文档中时,使用编辑器或浏览器打开这个文档,打开文档必须很迅速,不能等待大图片处理完成,这时需要做个图片Proxy来代替真正的图片。如果那个对象在Internet的某个远端服务器上,直接操作这个对象因为网络速度原因可能比较慢,那我们可以先用Proxy来代替那个对象。总之原则是,对于开销很大的对象,只有在使用它时才创建,这个原则可以为我们节省很多宝贵的Java内存. 所以,有些人认为Java耗费资源内存,我以为这和程序编制思路也有一定的关系。

(3)现实中,Proxy应用范围很广,现在流行的分布计算方式RMI和Corba等都是Proxy模式的应用


静态代理--接口

interface ClothFactory{
	public void productCloth();
}
静态代理--被代理类

class NikeClothFactory implements ClothFactory{

	@Override
	public void productCloth() {
		System.out.println("生产一批Nike衣服");
	}
}

class ADDSClothFactory implements ClothFactory{

	@Override
	public void productCloth() {
		System.out.println("生产一批ADDS衣服");
	}
	
}
静态代理--代理类

class Proxy implements ClothFactory{
<span style="white-space:pre">	</span>private ClothFactory cf;
<span style="white-space:pre">	</span>
<span style="white-space:pre">	</span>public Proxy(ClothFactory cf) {
<span style="white-space:pre">		</span>this.cf = cf;
<span style="white-space:pre">	</span>}


<span style="white-space:pre">	</span>@Override
<span style="white-space:pre">	</span>public void productCloth() {
<span style="white-space:pre">		</span>System.out.println("Proxy fee is $2000");
<span style="white-space:pre">		</span>cf.productCloth();
<span style="white-space:pre">	</span>}
}
静态代理--实体类

public class StaticProxy {
	
	@Test
	public void test(){
		Proxy proxy = new Proxy(new NikeClothFactory());
		proxy.productCloth();
		
		Proxy proxy2 = new Proxy(new ADDSClothFactory());
		proxy2.productCloth();
	}
}

动态代理类:

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

import org.junit.Test;

interface Subject {
	void action();
}

// 被代理类
class RealSubject implements Subject {

	@Override
	public void action() {
		System.out.println("real subject ...");
	}
}

/**
 * 动态代理类: 1)实现InvocationHandler接口 2)调用java.lang.Reflect.Proxy类中的静态方法:
 * newProxyInstance(ClassLoader loader, Class<?>[] interfaces,
 * InvocationHandler,h) ①.loader:与被代理类的类加载器一致 ②.interfaces:与被代理类实现的接口一致
 * ③.h:实现了InvocationHandler接口的类对象,通常为this
 */
class MyInvocationHandler implements InvocationHandler {
	// 实现了接口的被代理类的对象声明(这里指RealSubject类对象)
	Object object;

	/**
	 * 作用: 1.给被代理类对象实例化:就是给上面的Object对象实例化(RealSubject)
	 * 2.返回一个代理类对象:返回MyInvocationHandler对象
	 * 
	 * @param obj
	 * @return 返回MyInvocationHandler对象
	 */
	public Object blind(Object obj) {
		this.object = obj;
		return Proxy.newProxyInstance(obj.getClass().getClassLoader(), obj
				.getClass().getInterfaces(), this);
	}

	/**
	 * 当代理对象发起对重写方法的调用时,都会转为对如下invoke方法的调用
	 * 
	 */
	@Override
	public Object invoke(Object proxy, Method method, Object[] args)
			throws Throwable {
		method.invoke(object, args);
		return null;
	}

}

public class DynamicProxy {
	@Test
	public void test() {
		// 创建被代理类RealSubject对象
		RealSubject realSubject = new RealSubject();
		// 创建实现了InvocationHandler接口的类对象
		MyInvocationHandler handler = new MyInvocationHandler();
		// 调用blind(realSubject)方法,动态的返回一个同样实现了被代理(RealSubject)
		// 所实现接口的代理类(MyInvocationHandler)对象
		Object obj = handler.blind(realSubject);
		Subject subObject = (Subject)obj;
		//转到实现了InvocationHandler接口的类对象的invoke()方法
		subObject.action();
	}
}



發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章