Java反射机制的实现详解

2016-02-19 09:47 22 1 收藏

下面图老师小编要向大家介绍下Java反射机制的实现详解,看起来复杂实则是简单的,掌握好技巧就OK,喜欢就赶紧收藏起来吧!

【 tulaoshi.com - 编程语言 】

很多主流框架都使用了反射技术.像ssh框架都采用两种技术 xml做配置文件+反射技术.

与反射有关的类包.

java.lang.reflect.*;和java.lang.Class;

Java中所有类型(包括基本类型)都对应一个Class对象,这个Class就是java.lang.Class。即每一个类型,在Class中都有一个Class对象跟它对应.Class 没有公共构造方法。注意不是没有,是没有公共的.

如何获得Class对象
代码如下:

.针对每一个对象.getCalss(),可以得到对应的Class.
.Class.forName(String),String的写法:包名.类名.就会创建包名.类名对应的那个对象
注:1.2只适用于引用类型
.对于基本类型:封装类.TYPE代表了对应的基本类型的Class对象.Integer.TYPE对应的是int的Class对象
注:3只适用于基本类型
.类型,Class。第4种是通用的.
上面的4种方法,只有方法2是动态的,只要换一个包就可以了.它具有动态潜质.所以真正意义的想体现动态编程只能使用方法2.

每种类型的Class对象只有一个,即他们的地址只有一个,但是不同类型是不同的.

所以下面的打印结果都为true.
代码如下:

//对与引用类型
Class c1 = "".getClass();
Class c2 =     Class.forName("java.lang.String");
Class c3 = String.class;
System.out.println(c1 ==c2);//true
//对于基本类型
Class num1 = Integer.TYPE;
Class num2 = int.class;
System.out.println(num1 == num2);//true

反射获取类中的成员的相关方法

[获取构造根据参数类型](使用时一般用不带declared的)
代码如下:

ConstructorT getConstructor(Class?... parameterTypes)
      返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
 Constructor?[] getConstructors()
      返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
 ConstructorT getDeclaredConstructor(Class?... parameterTypes)
      返回一个 Constructor 对象,该对象反映此 Class 对象所表示的类或接口的指定构造方法。
 Constructor?[] getDeclaredConstructors()
      返回 Constructor 对象的一个数组,这些对象反映此 Class 对象表示的类声明的所有构造方法。

[获取属性根据属性名](使用时一般用是带declared的,因为属性一般都是私有的)
代码如下:

Field getField(String name)
      返回一个 Field 对象,它反映此 Class 对象所表示的类或接口的指定公共成员字段。
 Field[] getFields()
      返回一个包含某些 Field 对象的数组,这些对象反映此 Class 对象所表示的类或接口的所有可访问公共字段。
 Field getDeclaredField(String name)
      返回一个 Field 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明字段。
 Field[] getDeclaredFields()
      返回 Field 对象的一个数组,这些对象反映此 Class 对象所表示的类或接口所声明的所有字段。

[获取方法方法名加上参数类型](使用时一般用不带declared的)
代码如下:

Method getMethod(String name, Class?... parameterTypes)
      返回一个 Method 对象,它反映此 Class 对象所表示的类或接口的指定公共成员方法。
 Method[] getMethods()
      返回一个包含某些 Method 对象的数组,这些对象反映此 Class 对象所表示的类或接口(包括那些由该类或接口声明的以及从超类和超接口继承的那些的类或接口)的公共 member 方法。
 Method getDeclaredMethod(String name, Class?... parameterTypes)
      返回一个 Method 对象,该对象反映此 Class 对象所表示的类或接口的指定已声明方法。
 Method[] getDeclaredMethods()
      返回 Method 对象的一个数组,这些对象反映此 Class 对象表示的类或接口声明的所有方法,包括公共、保护、默认(包)访问和私有方法,但不包括继承的方法。
 T newInstance()
      创建此 Class 对象所表示的类的一个新实例。 new Instance()可以动态的创建对象
 String toString()
      将对象转换为字符串。

注意:

new Instance()调用的是无参构造,如果该类没有无参构造方法,则newInstance()会产生异常.

有declared的方法是支持私有,但是不支持继承,无declared的方法支持继承,不支持私有,且只能取出public的东西.

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

因此取属性的时候一般来说是带declared的,因为属性一般都是私有的,取方法时一般是不带declared的,取构造时一般也是不带declared的.

实例模拟反射获取类中的相关属性和方法

利用反射对属性赋值

Field中的方法

 Object get(Object obj)

  返回指定对象上此 Field 表示的字段的值。

      Field f = c.getXXField(属性名);

      值 = f.get(对象);

 void set(Object obj, Object value)

  将指定对象变量上此 Field 对象表示的字段设置为指定的新值。

  f.set(对象,值);

 Class? getType()

  返回一个 Class 对象,它标识了此 Field 对象所表示字段的声明类型。

      用于获取属性的类型(返回Class对象).
代码如下:

Class c = Student.class;
    Object obj  = c.newInstance();            //创建Student类的对象
    Field f = c.getDeclaredField("name");        //获取name属性
    f.setAccessible(true);                    //设置私有可以访问.
    f.set(obj, "zhangsan");
    System.out.println(f.get(obj));             //获取obj的name属性的值.

利用反射调用构造

对于构造真正调用是在调用newInstance()方法时.
代码如下:

Class c = Class.forName("com.clazz.reflect.Student");
    Constructor con = c.getConstructor();         //没有执行构造,
    Object cObj = c.getConstructor().newInstance();//调用无参的构造方法
    Constructor conAll = c.getConstructor(int.class,String.class,int.class);
    Object caobj = conAll.newInstance(1001,"zjamgs",234235);//调用含参的构造方法.
    System.out.println(caobj);                  //打印输出

利用反射调用方法

对象.方法名(值1,2,3);

Method m = c.getMethoed(方法名,参数类型...);

(本文来源于图老师网站,更多请访问http://www.tulaoshi.com/bianchengyuyan/)

m.invoke(对象,方法调用的参数 )如果底层方法所需的形参数为 0,则所提供的 args 数组长度可以为 0 或 null。
代码如下:

Class c = Class.forName("com.clazz.reflect.Student");
    Object obj = c.newInstance();    //创建Sutdent对象.
    Method msetName = c.getMethod("setName", String.class);//obj无须转换类型
    msetName.invoke(obj, "zhangsan");//调用方法setName, 并传参.
    Method msetId = c.getMethod("setId", int.class);
    msetId.invoke(obj, 409090202);
    System.out.println(obj);

反射应用实例

实体类
代码如下:

package org.dennisit.reflect.entity;
import java.io.Serializable;
/**
 *
 *  User.java   
 *
 *  @version : 1.1
 * 
 *  @author  : 苏若年    a href="mailto:DennisIT@163.com"发送邮件/a
 *   
 *  @since     : 1.0        创建时间:    2013-2-26        下午01:43:56
 *    
 *  TODO     :    class User.java is used for ...
 *
 */
public class User implements Serializable{

    private String test;

    public void execute(String name,int age){
        System.out.println("name=" + name + ",age=" + age);
    }
}

反射测试类
代码如下:

package org.dennisit.reflect.main;
import java.lang.reflect.Field;
/**
 *
 *  ReflectEx.java   
 *
 *  @version : 1.1
 * 
 *  @author  : 苏若年    a href="mailto:DennisIT@163.com"发送邮件/a
 *   
 *  @since     : 1.0        创建时间:    2013-2-26        下午01:46:00
 *    
 *  TODO     :    class ReflectEx.java is used for ...
 *
 */
public class ReflectEx {

    public static void main(String[] args)throws Exception {
        Class cls = Class.forName("org.dennisit.reflect.entity.User");
        Object obj = cls.newInstance();       //创建User的对象
        Field f = cls.getDeclaredField("test");    //获取test属性
        f.setAccessible(true);                    //打开私有属性test的访问权限
        f.set(obj, "zhangsan");                    //为test重新复制
        System.out.println(f.get(obj));            //获取obj的test属性值
        //根据方法名execute获取方法
        java.lang.reflect.Method m = cls.getMethod("execute", String.class, int.class);
        m.invoke(obj, "dennisit",23);            //调用execute方法
    }
}

运行效果
代码如下:

zhangsan
name=dennisit,age=23

编写一个反射动态实例化类的例子
代码如下:

package org.dennisit.reflect.main;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.util.Map;
import java.util.Set;
/**
 *
 *  DynamicReflect.java   
 *
 *  @version : 1.1
 * 
 *  @author  : 苏若年    a href="mailto:DennisIT@163.com"发送邮件/a
 *   
 *  @since     : 1.0        创建时间:    2013-2-26        下午01:58:12
 *    
 *  TODO     :    利用反射动态实例化的例子
 *
 */
public class DynamicReflect {

    public static Object getInstance(String className,MapString,Object map)throws Exception{
        Class c = Class.forName(className);
        Object obj = c.newInstance();                //对象对象
        SetString keys = map.keySet();            //获取对应的所有属性
        Field[] fAll = c.getDeclaredFields();        //获取类中所有属性
        for(int i=0;ifAll.length;i++){
            for(String key:keys){                    //循环匹配
                if(fAll[i].getName().equals(key)){    //如果用户传入的属性跟获取到的类中的属性名匹配
                    Field f = c.getDeclaredField(key);//获取该属性
                    //构建setXxx()方法名
                    String methodName = "set" + key.substring(0,1).toUpperCase()+key.substring(1);
                    Method method = c.getMethod(methodName, f.getType());//根据构建的用户名获取对应的方法
                    method.invoke(obj, map.get(key));//方法调用
                }else{
                    continue;
                }
            }
        }
        return obj;
    }
}

接下来我们测试我们编写的动态反射实例化例子

实体类
代码如下:

package org.dennisit.reflect.entity;
import java.io.Serializable;
/**
 *
 *  User.java   
 *
 *  @version : 1.1
 * 
 *  @author  : 苏若年    a href="mailto:DennisIT@163.com"发送邮件/a
 *   
 *  @since     : 1.0        创建时间:    2013-2-26        下午01:43:56
 *    
 *  TODO     :    实体类
 *
 */
public class User implements Serializable{

    private String name;
    private int age;
    private String email;

    public User() {  //必须有无参构造

    }

    //getter() and setter()   

}

主测试类
代码如下:

package org.dennisit.reflect.main;
import java.util.HashMap;
import java.util.Map;
import org.dennisit.reflect.entity.User;
/**
 *
 *  ReflectEx.java   
 *
 *  @version : 1.1
 * 
 *  @author  : 苏若年    a href="mailto:DennisIT@163.com"发送邮件/a
 *   
 *  @since     : 1.0        创建时间:    2013-2-26        下午01:46:00
 *    
 *  TODO     :    class ReflectEx.java is used for ...
 *
 */
public class ReflectEx {

    public static void main(String[] args)throws Exception {
        Class cls = Class.forName("org.dennisit.reflect.entity.User");
        String className = "org.dennisit.reflect.entity.User";
        MapString,Object map = new HashMapString, Object();
        map.put("name", "dennisit");
        map.put("age", 22);
        map.put("email", "dennisit@163.com");

        User user = (User)DynamicReflect.getInstance(className, map);
        System.out.println(user.getName() + "," + user.getAge() + "," + user.getEmail());
    }
}

程序运行结果
代码如下:

dennisit,22,dennisit@163.com

来源:http://www.tulaoshi.com/n/20160219/1592104.html

延伸阅读
由于本文旨在探讨Java"异常机制"的深层原理,因此关于"异常"的使用方法都不做详细说明。首先看一段非常熟悉的用于打开一个文件的C程序段: FILE *fp; fp=fopen(filename,"rw"); if(fp==NULL){ printf("cannot open file"); exit(0); } 在这段程序中,if条件语句中的一段用来...
标签: Java JAVA基础
一、在jdk1.2以后,类加载是通过委托来完成的,这意味着如果 ClassLoader 不能找到类,它会请求父代 ClassLoader 来执行此项任务,所有 ClassLoaders 的根是系统 ClassLoader,它会以缺省方式装入类 -- 即,从本地文件系统。今天我们就来探讨一下在jvm中这些机制是怎样运行的。让我们假设有一个class字节码文件(比如Hello.class...
作者:JavaResearch 大多数人认为,接口的意义在于顶替多重继承。众所周知Java没有c++那样多重继承的机制,但是却能够实现多个接口。其实这样做是很牵强的,接口和继承是完全不同的东西,接口没有能力代替多重继承,也没有这个义务。接口的作用,一言以蔽之,就是标志类的类别(type of class)。把不同类型的类归于不同的接口,可以更好的管...
学习过Java Swing的读者一定对于Swing中相对较为复杂的事件驱动模型比较困惑,虽然事件驱动模型在Java Swing中被完完全全的体现出来了,但是对于一个软件初学者而言这样的近乎“裸体”的事件驱动模型确实是很难理解的。 Microsoft公司.Net框架与Java Swing的GUI编程相比要简单很多,同样是事件驱动模型.Net框架就进行了大量的封装处理...
Java反射学习 所谓反射,可以理解为在运行时期获取对象类型信息的操作。传统的编程方法要求程序员在编译阶段决定使用的类型,但是在反射的帮助下,编程人员可以动态获取这些信息,从而编写更加具有可移植性的代码。严格地说,反射并非编程语言的特性,因为在任何一种语言都可以实现反射机制,但是如果编程语言本身支持反射,那么反射的实现就...

经验教程

642

收藏

6
微博分享 QQ分享 QQ空间 手机页面 收藏网站 回到头部