Java中的反射机制——动态编程

Java中的反射机制——动态编程

参考:
https://github.com/JustinSDK/JavaSE6Tutorial/blob/master/docs/CH16.md
《Java编程思想》

反射的作用

能够在运行时获取类的信息(而不是编译时),使java语言在运行时拥有一项“自观”的能力。
具体来说:

  • 在运行时判断任意对象所属的类;
  • 在运行时构造任意一个类的对象;
  • 在运行时判断任意一个类所具有的成员变量和方法;
  • 在运行时操作对象(操作方法,改变字段值(无所谓公有私有))。

通常是通过一个类创建对象,而反射方法就是通过一个对象找到一个类的信息。
可以参考一个实例:http://blog.csdn.net/ljphhj/article/details/12858767
判断对象所属的类

<1>Class object.getClass();
<2>Class 类.class;
<3>Class Class.forName(String className)//className必须是包含package的全名

均可以返回一个Class引用对象。这是在运行时获取各种类型信息的前提。
介绍几个Class对象常用的几个方法:

public class LocalTest {
public static void main(String[] args) {
    try {
        Class c = Class.forName("Models.Person.Enermy");
        System.out.println("类别名称:"+c.getName());
        System.out.println("父类为:" + c.getSuperclass());
        System.out.println("是否为接口:" + c.isInterface());
        System.out.println("是否为基本类型:" + c.isPrimitive());       
    } catch (ClassNotFoundException e) {
        // TODO Auto-generated catch block
        e.printStackTrace();
    }
}
}/*Output
类别名称:Models.Person.Enermy
父类为:class Models.Person.Person
是否为接口:false
是否为基本类型:false*/

构造类的对象

Class c = ...;
Object obj = c.newInstance();

可以对obj发送除Object之外的任何消息,前提是更多地了解obj并对其执行某种转型(instanceof)。
另外,使用newInstance()创建的类,必须带有默认的构造器。
当然还可以用其他反射API,用任意的构造器来动态地创建类的对象(Constructors).
获取类的成员变量和方法

  • 得到构造器

    Constructor[] getConstructors() //获得类的所有公共构造函数 
    Constructor[] getDeclaredConstructors() //获得类的所有构造函数 
    
  • 得到成员变量

    Field[] getFields() //获得类的公有字段 
    Field[] getDeclaredFields()  //获得类的所有字段
    
  • 得到方法

    Method[] getMethods() //获得类的所有公有方法
    Method[] getDeclaredMethods() //获得类的所有方法
    

操作对象
与JavaBean息息相关(各种setter与getter). 示例如下:

  • 执行方法:

    Method method = obj.getClass().getDeclaredMethod(methodName);
    method.setAccessible(true);
    method.invoke(obj);
    
  • 修改字段:

    Field field = obj.getClass().getDeclaredField(fieldName);
    field.setAccessible(true);
    field.setInt(obj,20);
    

详见invoke的使用。

instanceOf和equals

当检查两个对象是否相等时,instanceof和isInstance()生成的结果完全一样,equals和==的结果也一样,但这两组测试的结果却不同。

public class LocalTest {
public static void main(String[] args) {
    Person person = PersonFactory.create("Models.Person.Enermy");//Enermy extends Person
    System.out.println(person.getClass().getName());
    //instanceof
    System.out.println(person instanceof Person);
    //isInstance
    System.out.println(Person.class.isInstance(person));
    //equals
    System.out.println(person.getClass().equals(Person.class));
    //==
    System.out.println(person.getClass() == Person.class);      
     }
}

运行结果:

Models.Person.Enermy
true
true
false
false

instanceof保持了类型的概念,它指的是“你是这个类吗?你是这个类的派生类吗?”,如果用equals比较对象,就没有考虑继承——它或者是这个确切的类型,或者不是。

动态代理

代理是一种基本的设计模式,由代理对象控制原对象的引用,可以将额外的操作从“真实”对象中分离到不同的地方,并可以保护“真实”对象的访问权限。

静态代理:为确定的“真实”对象创建专用的代理。
动态代理:在运行期动态地创建代理并动态地处理对所代理方法的调用。

动态代理的使用步骤:
(1)创建动态代理
可以通过使用 Proxy.newProxyInstance()方法创建动态代理。

InvocationHandler handler = new MyInvocationHandler(new RealObject());
MyInterface proxy = (MyInterface) Proxy.newProxyInstance(
    MyInterface.class.getClassLoader(),
    new Class[] { MyInterface.class },
    handler);

newProxyInstance()方法有三个参数:

  • 类加载器(ClassLoader)用来加载动态代理类。
  • 一个要实现的接口数组。
  • InvocationHandler接口的一个实现。

(2)实现自己的InvocationHandler接口

public class MyInvocationHandler implements InvocationHandler{
    private Object proxied;
    public MyInvocationHandler(Object proxied){
        this.proxied = proxied;
    }

    public Object invoke(Object proxy, Method method, Object[] args)
    throws Throwable {
    //do something "dynamic"
    }
}
  • proxy参数是实现要代理接口的动态代理对象。通常你是不需要使用它的。
  • invoke()方法中的 Method 对象参数代表了被动态代理的接口中要调用的方法,从这个 method 对象中你可以获取到这个方法名字,方法的参数,参数类型等等信息。
  • Object数组参数包含了被动态代理的方法需要的方法参数。
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值