Java review--反射

来源:互联网 发布:网络机顶盒刷机包下载 编辑:程序博客网 时间:2024/06/03 16:32

为什么要使用反射?

对象在运行的时候有两种类型:编译时类型和运行时类型。运行时我们可能无法知道对象和类,程序只能靠运行时信息来发现该对象和类的真实信息,这就需要用到反射。 


获得Class对象

每个类被加载的时候,系统会为它生成一个对应的Class对象,通过Class对象,就可以访问到JVM的这个类。Java中获取Class对象通常采用3种方式:

1.使用Class类的forName(String clazzName)静态方法。

2.调用某个类的.class属性获取当前的Class对象。

3.调用某个对象的getClass()方法。

第一种方式和第二种方式都是直接根据类来取得该类的Class对象,对比一下,第二种优势:代码更安全(编译阶段可以检查Class对象是否存在),程序性能好(不用调方法)。


从Class中获取信息

Class提供的功能非常丰富,它可以获取该类包含的构造器、方法、内部类、属性信息等。


使用反射操作对象


对象的创建

反射生成对象有两种方式:

1.使用Class对象的NewInstance()方法来创建类的实例。要求:类有默认构造器。

2.使用Class对象获取指定的Constructor对象(getConstructor()方法),再调用Constructor对象的newInstance()方法来创建Class对象对应的实例。


调用方法

获取该类对应的Class对象后,通过Class对象的getMethods()方法或者getMethod()方法来获取全部方法。每个Method里面有一个invoke方法Object invoke(Object obj,Object...args):obj是执行方法的主调,后面的args是执行方法时传入方法的实参。


访问属性

通过Class对象的getFields()或者getField()获取该类全部的或者指定的Field。


反射和JDK动态代理

JDK动态代理只为接口创建动态代理,下面有一个动态代理的demo:

Test.java

<span style="font-size:14px;">public class Test {public static void main(String[] args) {Dog target =new GunDog();Dog dog =(Dog)MyProxyFactory.getProxy(target);dog.info();dog.run();}}   </span>

Dog.java
<span style="font-size:14px;">public interface Dog { void info(); void run();}</span>

GunDog.java

<span style="font-size:14px;">public class GunDog implements Dog {public void info(){System.out.println("我是一个只猎狗");}public void run(){System.out.println("我会跑");}}</span>

MyProxyFactory.java
<span style="font-size:14px;">import java.lang.annotation.Target;import java.lang.reflect.Proxy;public class MyProxyFactory {public static Object getProxy(Object target){//创建一个MyInvokationHandler对象MyInvocationHandler handler =new MyInvocationHandler();handler.setTarget( target);//创建一个动态代理return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), handler);}}</span>

MyInvocationHandler.java
<span style="font-size:14px;">import java.lang.annotation.Target;import java.lang.reflect.InvocationHandler;import java.lang.reflect.Method;import org.omg.CORBA.PRIVATE_MEMBER;public class MyInvocationHandler implements InvocationHandler {private Object target;public void setTarget(Object target){this.target =target;}//执行动态代理对象的所有方法时,都会被替代成执行如下的invoke方法public Object invoke(Object proxy, Method method, Object[] args)throws Throwable {DogUtil du=new DogUtil();//执行DogUtil 对象中的method1方法du.method1();//以Target为主调来执行method方法,回调了target的原有方法Object result=method.invoke(target, args); du.method2();return result;}}</span>


运行结果:



  Proxy和InvocationHandler就可以实现,当程序调用info()方法和run()方法时,系统可以自动的将method1()和method2()两个通用方法插入info()和run()方法中执行。

  MyInvocationHandler类,该实现类的invoke()方法将会作为代理对象的方法实现。

       MyProxyFactory动态代理工厂类提供了一个getProxy方法, 该方法为target对象生成一个动态代理对象,这个动态代理对象与target实现了同样的接口。当调用动态代理对象指定的方法的时候,实际将变成执行MyInvocationHandler对象的invoke方法。

      从这个例子中可以发现,动态代理十分的灵活,代理类不仅仅可以实现被代理类要实现的接口,而且可以动态的扩展一些公共的方法,在原实现的前,后。









0 0
原创粉丝点击