首页 > 代码库 > Java反射以及动态代理(上)

Java反射以及动态代理(上)

  在常用的各种框架中,反射与动态代理很常见,也很重要。本篇就对这一小节的内容基础性地总结。

  首先需要了解什么是类型信息,以及RTTI与反射的关系与区别。

  Java中,使用Class对象来表示所有类的对象。利用Class对象来获取类中的成员变量,构造函数以及方法,这些内容我们称之为类型信息。RTTI的含义是,在运行时识别一个对象的类型,但有一个前提,就是类型在编译时必须已知,这样才能用RTTI识别,并利用这些信息做一些有用的事情。但是如果在编译时,程序没有办法获知到这个对象所属的类,怎样才能使用这个类呢?答案是,我们可以在运行时,让JVM加载这个类的Class对象。由于没有经过编译期的检查,所以这里在使用之前,JVM也要简单地检查这个对象,看它属于哪个特定的类,而后加载这个类的Class对象。所以RTTI与反射的区别就在于,前者是在编译时打开和检查.class文件,运行时加载所需的类的Class对象,而后者则是在运行时打开和检查.class文件,并加载所需要类的Class对象。

  举个例子:

class Test{    public static void main(String[] args){        new Dev();    }}

在对它进行编译时,如果包下没有Dev这个类,那么编译会报错:

C:\Users\BruceChan\Desktop\test>javac Test.javaTest.java:3: 错误: 找不到符号                new Dev();                    ^  符号:   类 Dev  位置: 类 Test1 个错误

但如果我们修改为反射的方式:

class Test{    public static void main(String[] args){        try{            Class.forName("Dev");        }catch(ClassNotFoundException e){            System.out.print(e.toString());        }        }}

对其进行编译时会发现,即便在没有Dev这个类存在的情况下,编译还是会顺利进行,因为它是在运行时,用到这个Dev类时,才会加载这个类。

---------------------------------------------------------------------------------->

  接下来,这里用代码的形式小节一下反射技术中,常用的套路。反射中,有三种方法可以获得类型的Class对象:

try {    Class cls1 = Class.forName("com.changjiang.test.RFP01.testReflect.MyClass");} catch (ClassNotFoundException e) {    e.printStackTrace();}
MyClass myClass
= new MyClass();Class cls2 = myClass.getClass();Class cls3 = MyClass.class;

通过该类的Class对象,可以获得它的属性,方法,构造函数,这里只说一下它的方法调用,首先给出原始类:

package com.changjiang.test.RFP01.testReflect;import java.util.Date;public class MyClass {    private int myInt;    private String myString;    public MyClass(){    }    public MyClass(int a){        this.myInt = a;        System.out.println(a);    }    public void Method2Void(){    }    public int Method2Int(){        System.out.println("Method2Int has run");        return 0;    }    public String Method2String(){        return "";    }    public Object Method2Object() {        return new Date();    }    public void Method3Param(int a, String b){        System.out.println("Method3Param has run with param-a:" + a + " and param-b:" + b);    }}

再给出几个方法的调用以及输出:

package com.changjiang.test.RFP01;import java.lang.reflect.Constructor;import java.lang.reflect.Method;import com.changjiang.test.RFP01.testReflect.MyClass;public class Main {    public static void main(String[] args) {        MyClass myClass = new MyClass();        Class cls = myClass.getClass();        try{               Method m = cls.getMethod("Method2Int", new Class[]{});//获取一个类的方法               m.invoke(myClass, new Object[]{});//精髓所在,调用这个类的方法                            Method m2 = cls.getMethod("Method3Param", new Class[]{int.class, String.class});               m2.invoke(myClass, new Object[]{5, "fake"});//调用这个类的方法,带参数的                            Constructor<MyClass> cons = cls.getConstructor(new Class[]{int.class});             cons.newInstance(47);         }catch(Exception e){               e.printStackTrace();           }           Method[] ms = cls.getMethods();           for(Method m:ms){               System.out.print(m.getName()+"\t");           }    }}

output:

Method2Int has run
Method3Param has run with param-a:5 and param-b:fake
47
Method2Int Method3Param Method2String Method2Object Method2Void wait wait wait equals toString hashCode getClass notify notifyAll

 ---------------------------------------------------------------------------------->

  OK,说到这里,我们该了解一下代理模式。清楚之后,我们再看动态代理。代理模式,简单地说,就是一个接口,两个实现。实现一中我们需要做一些事情,在实现二中,我们不仅要做实现一中的事情,而且可以在此之前与之后都添加我们想要做的别的事情。具体内容看看代码。

package com.changjiang.test.RFP01.testReflect;public class SampleProxy {    public static void main(String[] args) {        new BaseSample1().doSomething();        System.out.println("--------------------------------");        new ProxySample(new BaseSample1()).doSomething();;    }}interface BaseInterface{    public void doSomething();}class BaseSample1 implements BaseInterface{    public void doSomething() {        System.out.println("BaseSample1");    }}class ProxySample implements BaseInterface{    private BaseInterface bi;    public ProxySample(BaseInterface bi) {        this.bi = bi;    }    public void doSomething() {        System.out.println("before");        bi.doSomething();        System.out.println("after");    }}

这里的接口,被两个类实现,一个是原生类,另一个是代理类,而代理类中不但实现了这个接口,还需要将代理类通过构造器赋给自己的属性中,而后在接口实现方法中使用原始类的方法。

 ---------------------------------------------------------------------------------->

接下来看看动态代理,主要是如何实现动态代理以及核心类Proxy与其方法newProxyInstance(ClassLoader loader, Class<?>[] interfaces, InovationHandler h)中几个参数的详细含义与作用剖析。(下篇)

Java反射以及动态代理(上)