Java反射机制的实现详解_java

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

时间: 2024-11-18 15:26:08

Java反射机制的实现详解_java的相关文章

Java静态方法不具有多态性详解_java

动态绑定机制使得基类的引用能够指向正确的子类对象,从而使得面向基类编程成为可能. 然而动态绑定在以下两种情况会失效. 1.基类方法是private或final修饰的 这个很好理解,因为private说明该方法对子类是不可见的,子类再写一个同名的方法并不是对父类方法进行复写(Override),而是重新生成一个新的方法,也就不存在多态的问题了.同理也可以解释final,因为方法同样是不可覆盖的. 2.方法是static修饰的 代码如下所示. class Base { public static v

基于Java中字符串内存位置详解_java

前言 之前写过一篇关于JVM内存区域划分的文章,但是昨天接到蚂蚁金服的面试,问到JVM相关的内容,解释一下JVM的内存区域划分,这部分答得还不错,但是后来又问了Java里面String存放的位置,之前只记得String是一个不变的量,应该是要存放在常量池里面的,但是后来问到new一个String出来应该是放到哪里的,这个应该是放到堆里面的,后来又问到String的引用是放在什么地方的,当时傻逼的说也是放在堆里面的,现在总结一下:基本类型的变量数据和对象的引用都是放在栈里面的,对象本身放在堆里面,

Java中Properties的使用详解_java

Java中有个比较重要的类Properties(Java.util.Properties),主要用于读取Java的配置文件,各种语言都有自己所支 持的配置文件,配置文件中很多变量是经常改变的,这样做也是为了方便用户,让用户能够脱离程序本身去修改相关的变量设置.今天,我们就开始Properties的使用. Java中Properties的使用 Properties的文档说明: The Properties class represents a persistent set of propertie

java 反射和动态代理详解及实例代码_java

一.java中的反射 1.通过反射加载类的属性和方法实例代码: /** * java.lang.Class 是反射的源头 * 我们创建了一个类,通过编译(javac.exe)生成对应的class文件,之后我们通过java.exe加载(jvm的类加载器加载)此class文件 * 此class文件加载到内存后,就是一个运行时类,存在缓存区,这个运行时类本事就是一个Class的实例 * 每一个运行时类只加载一次, */ Class<StudentExam> clazz = StudentExam.c

Java 23种设计模型详解_java

设计模式(Design Patterns)                                   --可复用面向对象软件的基础 设计模式(Design pattern)是一套被反复使用.多数人知晓的.经过分类编目的.代码设计经验的总结.使用设计模式是为了可重用代码.让代码更容易被他人理解.保证代码可靠性. 毫无疑问,设计模式于己于他人于系统都是多赢的,设计模式使代码编制真正工程化,设计模式是软件工程的基石,如同大厦的一块块砖石一样.项目中合理的运用设计模式可以完美的解决很多问题,每

Java线程间的通信方式详解_java

本总结我对于JAVA多线程中线程之间的通信方式的理解,主要以代码结合文字的方式来讨论线程间的通信,故摘抄了书中的一些示例代码,具体内容如下 ①同步 这里讲的同步是指多个线程通过synchronized关键字这种方式来实现线程间的通信. 参考示例: public class MyObject { synchronized public void methodA() { //do something.... } synchronized public void methodB() { //do so

java equals和==的区别详解_java

大概说equals和==都比较的是什么: 1. boolean tem = a == b; 首先==比较的肯定是地址,从堆栈的角度说也就是说==比较的是栈上面的内容.因为栈是用来存放地址或是java中八大基本类型中自动变量的字面值(自动变量就是用int a = 1;这种形式来定义的变量).如果是自动变量比较值的话肯定是用==来比较,因为equals()是一个方法,所以必须由对象调用才可以用于比较.而自动变量既不是类的实例也不是类的引用所以不能用equals()方法. 2.boolean tem

Java反射机制(Reflection)浅析_java

Reflection也就是反射,是Java语言的一个重要特征,我们知道,在使用一个类之前,我们往往都已经创建好它了,比如创建一个类文件,然后再写些属性.方法等,也就是这种类是静态的,但反射机制却允许你动态地创建一个类.除了动态地创建一个类外,我们还能动态地获取同类对象的数据,并将这些数据赋给新创建的类,这有点类似克隆复制.在很多时候,我们都需要这种动态创建类的特征,比如在处理一些业务,但这些业务却又稍有区别的时候,往往对应着多个类,在处理的时候,我们就要根据不同的业务处理来调用不同的类,这个时候

Java中Map的排序问题详解_java

Map的种类 在Java中,Map的主要作用是存储键值对.由于是根据键得到值,所以不允许键重复.它主要有如下几个类别: HashMap: 最常用的Map,它根据键的HashCode值存储数据,根据键可以直接获取它的值,具有很快的访问速度,遍历时,取得数据的顺序是完全随机的.HashMap最多只允许一条记录的键为Null;允许多条记录的值为Null;HashMap不支持线程的同步,即任一时刻可以有多个线程同时写HashMap;可能会导致数据的不一致.如果需要同步,可以用Collections的sy