欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

Java反射机制的实现详解

程序员文章站 2023-12-10 18:17:22
很多主流框架都使用了反射技术.像ssh框架都采用两种技术 xml做配置文件+反射技术. 与反射有关的类包. java.lang.reflect.*;和java.lang...

很多主流框架都使用了反射技术.像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)

复制代码 代码如下:

constructor<t> getconstructor(class<?>... parametertypes)
      返回一个 constructor 对象,它反映此 class 对象所表示的类的指定公共构造方法。
 constructor<?>[] getconstructors()
      返回一个包含某些 constructor 对象的数组,这些对象反映此 class 对象所表示的类的所有公共构造方法。
 constructor<t> 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的东西.

因此取属性的时候一般来说是带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(方法名,参数类型...);

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,map<string,object> map)throws exception{
        class c = class.forname(classname);
        object obj = c.newinstance();                //对象对象
        set<string> keys = map.keyset();            //获取对应的所有属性
        field[] fall = c.getdeclaredfields();        //获取类中所有属性
        for(int i=0;i<fall.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";
        map<string,object> map = new hashmap<string, 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