反射

来源:互联网 发布:软件测试感想 编辑:程序博客网 时间:2024/06/05 14:50

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 {@Testpublic 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 */@Testpublic 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  */@Testpublic 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  */@Testpublic 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  */@Testpublic 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  */@Testpublic 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  */@Testpublic 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)访问私有属性时,让这个属性可见

/** * 调用指定属性  */@Testpublic 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对象的参数信息。

/** * 调用指定方法  */@Testpublic 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{@Overridepublic void productCloth() {System.out.println("生产一批Nike衣服");}}class ADDSClothFactory implements ClothFactory{@Overridepublic 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 {@Testpublic 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 {@Overridepublic 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方法的调用 *  */@Overridepublic Object invoke(Object proxy, Method method, Object[] args)throws Throwable {method.invoke(object, args);return null;}}public class DynamicProxy {@Testpublic 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();}}



0 0
原创粉丝点击