热门标签 | HotTags
当前位置:  开发笔记 > 运维 > 正文

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 getConstructor(Class... parameterTypes)
      返回一个 Constructor 对象,它反映此 Class 对象所表示的类的指定公共构造方法。
 Constructor[] getConstructors()
      返回一个包含某些 Constructor 对象的数组,这些对象反映此 Class 对象所表示的类的所有公共构造方法。
 Constructor 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 对象所表示的类的一个新实例。
 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  : 苏若年    发送邮件
 *   
 *  @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  : 苏若年    发送邮件
 *   
 *  @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  : 苏若年    发送邮件
 *   
 *  @since     : 1.0        创建时间:    2013-2-26        下午01:58:12
 *    
 *  TODO     :    利用反射动态实例化的例子
 *
 */
public class DynamicReflect {

    public static Object getInstance(String className,Map map)throws Exception{
        Class c = Class.forName(className);
        Object obj = c.newInstance();                //对象对象
        Set keys = map.keySet();            //获取对应的所有属性
        Field[] fAll = c.getDeclaredFields();        //获取类中所有属性
        for(int i=0;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  : 苏若年    发送邮件
 *   
 *  @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  : 苏若年    发送邮件
 *   
 *  @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 map = new HashMap();
        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


推荐阅读
  • HDFS2.x新特性
    一、集群间数据拷贝scp实现两个远程主机之间的文件复制scp-rhello.txtroothadoop103:useratguiguhello.txt推pushscp-rr ... [详细]
  • eclipse学习(第三章:ssh中的Hibernate)——11.Hibernate的缓存(2级缓存,get和load)
    本文介绍了eclipse学习中的第三章内容,主要讲解了ssh中的Hibernate的缓存,包括2级缓存和get方法、load方法的区别。文章还涉及了项目实践和相关知识点的讲解。 ... [详细]
  • Spring源码解密之默认标签的解析方式分析
    本文分析了Spring源码解密中默认标签的解析方式。通过对命名空间的判断,区分默认命名空间和自定义命名空间,并采用不同的解析方式。其中,bean标签的解析最为复杂和重要。 ... [详细]
  • 本文介绍了使用AJAX的POST请求实现数据修改功能的方法。通过ajax-post技术,可以实现在输入某个id后,通过ajax技术调用post.jsp修改具有该id记录的姓名的值。文章还提到了AJAX的概念和作用,以及使用async参数和open()方法的注意事项。同时强调了不推荐使用async=false的情况,并解释了JavaScript等待服务器响应的机制。 ... [详细]
  • Java序列化对象传给PHP的方法及原理解析
    本文介绍了Java序列化对象传给PHP的方法及原理,包括Java对象传递的方式、序列化的方式、PHP中的序列化用法介绍、Java是否能反序列化PHP的数据、Java序列化的原理以及解决Java序列化中的问题。同时还解释了序列化的概念和作用,以及代码执行序列化所需要的权限。最后指出,序列化会将对象实例的所有字段都进行序列化,使得数据能够被表示为实例的序列化数据,但只有能够解释该格式的代码才能够确定数据的内容。 ... [详细]
  • 本文介绍了Java工具类库Hutool,该工具包封装了对文件、流、加密解密、转码、正则、线程、XML等JDK方法的封装,并提供了各种Util工具类。同时,还介绍了Hutool的组件,包括动态代理、布隆过滤、缓存、定时任务等功能。该工具包可以简化Java代码,提高开发效率。 ... [详细]
  • android listview OnItemClickListener失效原因
    最近在做listview时发现OnItemClickListener失效的问题,经过查找发现是因为button的原因。不仅listitem中存在button会影响OnItemClickListener事件的失效,还会导致单击后listview每个item的背景改变,使得item中的所有有关焦点的事件都失效。本文给出了一个范例来说明这种情况,并提供了解决方法。 ... [详细]
  • 本文讨论了Alink回归预测的不完善问题,指出目前主要针对Python做案例,对其他语言支持不足。同时介绍了pom.xml文件的基本结构和使用方法,以及Maven的相关知识。最后,对Alink回归预测的未来发展提出了期待。 ... [详细]
  • 本文讲述了如何通过代码在Android中更改Recycler视图项的背景颜色。通过在onBindViewHolder方法中设置条件判断,可以实现根据条件改变背景颜色的效果。同时,还介绍了如何修改底部边框颜色以及提供了RecyclerView Fragment layout.xml和项目布局文件的示例代码。 ... [详细]
  • 在说Hibernate映射前,我们先来了解下对象关系映射ORM。ORM的实现思想就是将关系数据库中表的数据映射成对象,以对象的形式展现。这样开发人员就可以把对数据库的操作转化为对 ... [详细]
  • 本文介绍了在SpringBoot中集成thymeleaf前端模版的配置步骤,包括在application.properties配置文件中添加thymeleaf的配置信息,引入thymeleaf的jar包,以及创建PageController并添加index方法。 ... [详细]
  • 本文讨论了在Spring 3.1中,数据源未能自动连接到@Configuration类的错误原因,并提供了解决方法。作者发现了错误的原因,并在代码中手动定义了PersistenceAnnotationBeanPostProcessor。作者删除了该定义后,问题得到解决。此外,作者还指出了默认的PersistenceAnnotationBeanPostProcessor的注册方式,并提供了自定义该bean定义的方法。 ... [详细]
  • ZSI.generate.Wsdl2PythonError: unsupported local simpleType restriction ... [详细]
  • XML介绍与使用的概述及标签规则
    本文介绍了XML的基本概念和用途,包括XML的可扩展性和标签的自定义特性。同时还详细解释了XML标签的规则,包括标签的尖括号和合法标识符的组成,标签必须成对出现的原则以及特殊标签的使用方法。通过本文的阅读,读者可以对XML的基本知识有一个全面的了解。 ... [详细]
  • Java验证码——kaptcha的使用配置及样式
    本文介绍了如何使用kaptcha库来实现Java验证码的配置和样式设置,包括pom.xml的依赖配置和web.xml中servlet的配置。 ... [详细]
author-avatar
0雕雕_970
这个家伙很懒,什么也没留下!
PHP1.CN | 中国最专业的PHP中文社区 | DevBox开发工具箱 | json解析格式化 |PHP资讯 | PHP教程 | 数据库技术 | 服务器技术 | 前端开发技术 | PHP框架 | 开发工具 | 在线工具
Copyright © 1998 - 2020 PHP1.CN. All Rights Reserved | 京公网安备 11010802041100号 | 京ICP备19059560号-4 | PHP1.CN 第一PHP社区 版权所有