Java学习之反射机制

前段时间在做项目的时候,由于是用的纯Servlet基础框架进行开发的,没有用到那些集成的框架,后来在后台处理表单中的数据的时候,感觉有很多东西都是重复的,比较繁琐,例如获取到前台页面表单中的值之后,要在后台实例化一个对象并且调用定义的setter方法来给对象赋值,由于表单中的数据比较多,然后这个调用setter方法的代码就显得有些重复臃肿,后来网上查资料才了解到可以通过java中的反射机制简化这一操作,并且也知道了很多框架里面也都用到了反射。。。

一、什么是反射机制

JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法;对于任意一个对象,都能够调用它的任意一个方法和属性;这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制。

简单的来说,反射机制指的是程序在运行时能够获取到自身的一些信息,在java中,只要给定类的名字,那么就可以通过反射机制来获取类的所有相关信息。

二、应用场合

其实在之前的时候,就已经接触过了反射机制,Java中使用JDBC操作数据库的时候,只是那个时候还不知道专业术语叫“反射机制”,例如:加载数据库的驱动类的代码。Class.forName(“com.mysql.jdbc.Driver”) ; 通过了解之后才知道原来这就是反射机制,并且也知道了很多集成的开发框架都有用到反射机制,像hibernate、struts等集成框架基本上都是通过反射机制去实现的。

三,示例

package com.wx.utils.tool;

import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.DateFormat;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashMap;
import java.util.Map;
import java.util.Map.Entry;

import com.wx.pojo.repair.RepairProduct;

/**
 * 类的反射机制
 * 通过java中的反射机制,动态的给对象属性赋值,并且获取对象属性值
 * @remark
 * @author feizi
 * @time 2015-2-5下午4:07:03
 */
public class ClassRefUtil {

    public static void main(String[] args) {
        //构建map集合,存放值
        Map<String, String> fieldValueMap = new HashMap<String, String>();
        fieldValueMap.put("id", "10010");
        fieldValueMap.put("cust_tax_code", "440232323232323");
        fieldValueMap.put("cust_name", "飞子科技");
        fieldValueMap.put("contact", "飞子");
        fieldValueMap.put("tel", "15623232323");
        fieldValueMap.put("addr", "飞子广场");
        fieldValueMap.put("product", "飞机");
        fieldValueMap.put("notes", "飞不起来");
        fieldValueMap.put("create_time", "2015-02-06 12:23:55");

        //类的全路径(带包名)
        String className = "com.wx.pojo.repair.RepairProduct";
        Object obj = null;

        try {
            //根据类的路径(类名)来创建Class对象
            Class<?> c = Class.forName(className);

            //创建类的实例
            obj = c.newInstance();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (InstantiationException e) {
            e.printStackTrace();
        } catch (IllegalAccessException e) {
            e.printStackTrace();
        }

        //通过反射赋值
        setFieldValue(obj, fieldValueMap);

        //通过反射取值
        int i = 0;
        Map<String, String> getFieldValueMap = getFieldValueMap(obj);

        /**
         * 1、这个对所有的对象都是通用的
         */
        System.out.println("\n\n=========输出调用get方法后取到的值==========");
        for (Entry<String, String> entry : getFieldValueMap.entrySet()) {
            System.out.println("[字段 "+(++i)+"] ["+entry.getKey()+"]   ---   [" + entry.getValue()+"]");
        }

        /**
         * 2、通过反射方式动态调用set方法赋值,通过原生get方式取值
         * 也可以通过下面这种方式,直接调用类中定义的get方法进行取值
         * 只是需要先把obj对象通过强制类型转换强转成我们需要操作的对象类型
         */
        /*RepairProduct product = (RepairProduct) obj;
        System.out.println("id:"+product.getId());
        System.out.println("cust_tax_code:"+product.getCust_tax_code());
        System.out.println("cust_name:"+product.getCust_name());
        System.out.println("contact:"+product.getContact());
        System.out.println("tel:"+product.getTel());
        System.out.println("addr:"+product.getAddr());
        System.out.println("product:"+product.getProduct());
        System.out.println("notes:"+product.getNotes());
        System.out.println("create_time:"+product.getCreate_time());
        System.out.println("order:"+product.getOrder());*/
    }

    /**
     * 通过反射调用get方法取值,并且以属性名称,和属性值以键值对的形式放于Map集合中
     * @param Object obj
     * @return
     */
    public static Map<String, String> getFieldValueMap(Object obj){
        try {
            //通过getClass方法获得obj类的类类型(即Class类型)
            Class<?> c = obj.getClass();

            //定义一个Map集合,存放get方法获取的值
            Map<String, String> getFieldValueMap = new HashMap<String, String>();

            //获取obj对象中自身定义的所有方法,包括public,private,protected
            //(也可以用c.getMethods(),只不过这个是获取obj中所有共有的方法,包括从父类继承的或从接口实现的所有public方法)
            Method[] methods = c.getDeclaredMethods();

            //获取obj对象中自身定义的所有属性变量
            Field[] fields = c.getDeclaredFields();

            if(null != fields && fields.length > 0){
                //遍历fields数组
                for (Field field : fields) {
                    //获取属性的定义名称
                    String fieldName = field.getName();

                    //获取属性的定义类型
                    String fieldType = field.getType().getSimpleName();

                    //拼接属性的get方法
                    String fieldGetMethodName = defineGetOrSetMethod(fieldName,"get");

                    //判断该属性是否定义了get方法
                    if (!checkGetOrSetMethod(methods, fieldGetMethodName)) {
                        continue;
                    }

                    //获取类中定义的get方法
                    Method fieldGetMethod = c.getMethod(fieldGetMethodName, new Class[]{});

                    //调用get方法获取值
                    Object fieldVal = fieldGetMethod.invoke(obj, new Object[]{});

                    String result = null;

                    if("Date".equals(fieldType)){
                        result = date2String((Date)fieldVal);
                    }else{
                        if(null != fieldVal){
                            result = String.valueOf(fieldVal);
                        }
                    }
                    getFieldValueMap.put(fieldName, result);
                }
            }

            return getFieldValueMap;
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;
    }

    /**
     * 传递Map集合,通过反射调用set方法给属性动态赋值,
     * @param Object obj
     * @param fieldValueMap
     */
    public static void setFieldValue(Object obj,Map<String, String> fieldValueMap){
        try {
            //通过getClass方法获得obj类的类类型(即Class类型)
            Class<?> c = obj.getClass();

            //获取对象中自身定义的所有方法
            Method[] methods = c.getDeclaredMethods();

            //获取对象中自身定义的所有属性
            Field[] fields = c.getDeclaredFields();

            //遍历fields属性数组
            if(null != fields && fields.length > 0){
                for (Field field : fields) {

                    //获取属性的定义名称
                    String fieldName = field.getName();

                    //拼接属性的set方法(自定义的set方法)
                    String fieldSetMethodName = defineGetOrSetMethod(fieldName,"set");

                    //判断该属性是否定义了set方法
                    if (!checkGetOrSetMethod(methods, fieldSetMethodName)) {
                        continue;
                    }

                    //获取类中定义的set方法
                    Method fieldSetMethod = c.getMethod(fieldSetMethodName, field.getType());

                    //取出map集合中需要操作的属性值
                    String fieldValue = fieldValueMap.get(fieldName);

                    if(!isBlank(fieldValue)){
                        //获取属性的定义类型
                        String fieldType = field.getType().getSimpleName();

                        //根据参数类型判断,调用不同的set方法
                        if("String".equals(fieldType)){
                            fieldSetMethod.invoke(obj, fieldValue);
                        }else if("Date".equals(fieldType)){
                            fieldSetMethod.invoke(obj, string2Date(fieldValue));
                        }else if(("Integer".equals(fieldType)) || ("int".equals(fieldType))){
                            fieldSetMethod.invoke(obj, Integer.parseInt(fieldValue));
                        }else if("Long".equalsIgnoreCase(fieldType)){
                            fieldSetMethod.invoke(obj, Long.parseLong(fieldValue));
                        }else if("Double".equalsIgnoreCase(fieldType)){
                            fieldSetMethod.invoke(obj, Double.parseDouble(fieldValue));
                        }else if("Boolean".equalsIgnoreCase(fieldType)){
                            fieldSetMethod.invoke(obj, Boolean.parseBoolean(fieldValue));
                        }else{
                            //没有合适的类型匹配
                            System.out.println("not suitable type" + fieldType);
                        }

                        /**
                         * 当然也可以通过下列这种方式来判断参数的类型,不过还是觉得上面那种方式判断简洁一些,下面要多写一些代码
                         */

                        /*Class[] paramTypes = fieldSetMethod.getParameterTypes();
                        System.out.println("方法的参数类型-paramTypes:"+Arrays.toString(paramTypes));

                        if(paramTypes[0] == String.class){
                            fieldSetMethod.invoke(obj, fieldValue);
                        }else if(paramTypes[0] == Date.class){
                            fieldSetMethod.invoke(obj, string2Date(fieldValue));
                        }else if((paramTypes[0] == Integer.class) || (paramTypes[0] == int.class)){
                            fieldSetMethod.invoke(obj, Integer.parseInt(fieldValue));
                        }else if((paramTypes[0] == Long.class) || (paramTypes[0] == long.class)){
                            fieldSetMethod.invoke(obj, Long.parseLong(fieldValue));
                        }else if((paramTypes[0] == Double.class) || (paramTypes[0] == double.class)){
                            fieldSetMethod.invoke(obj, Double.parseDouble(fieldValue));
                        }else if((paramTypes[0] == Boolean.class) || (paramTypes[0] == boolean.class)){
                            fieldSetMethod.invoke(obj, Boolean.parseBoolean(fieldValue));
                        }else{
                            //没有合适的类型匹配
                            System.out.println("not suitable type" + fieldType);
                        }*/

                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
    }

    /**
     * 拼接属性的  get 方法 或   set 方法
     * 因为我们自身在定义getter方法的时候,都是将属性名的第一个字母转成大写了
     * @return
     */
    public static String defineGetOrSetMethod(String fieldName,String methodType){
        if(isBlank(fieldName)){
            return null;
        }

        //这里也可以直接用“get 或   set”+属性名称,(属性名称的首字母也可以不用转换成大写,上面判断的时候用equalsIgnoreCase忽略大小写就可以了)
        return methodType + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);
    }

    /**
     * String字符串转Date日期格式
     * @param dateStr
     * @return
     */
    public static Date string2Date(String dateStr){
        if(isBlank(dateStr)){
            return null;
        }

        try {
            String fmtStr = null;
            if(dateStr.indexOf(":") > 0){
                fmtStr = "yyyy-MM-dd HH:mm:ss";
            }else{
                fmtStr = "yyyy-MM-dd";
            }

            DateFormat df = new SimpleDateFormat(fmtStr);

            return df.parse(dateStr);
        } catch (ParseException e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 日期转字符串
     * @param date
     * @return
     */
    public static String date2String(Date date){
        if(null == date){
            return null;
        }

        try {
            DateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
            return df.format(date);
        } catch (Exception e) {
            e.printStackTrace();
        }
        return null;
    }

    /**
     * 判断某个属性是否定义了gettter和setter方法
     * @param methods
     * @param fieldMethodName
     * @return
     */
    public static boolean checkGetOrSetMethod(Method[] methods,String fieldMethodName){
        boolean flag = false;

        if (null != methods && methods.length > 0) {
            for (Method method : methods) {
                if(fieldMethodName.equals(method.getName())){
                    flag = true;
                }
            }
        }
        return flag;
    }

    /**
     * 判空
     * @param str
     * @return
     */
    public static boolean isBlank(String str){
        if(null == str || str.trim().length() == 0){
            return true;
        }
        return false;
    }
}

运行main方法后的效果:

四、在程序中进行调用,这里是在Servlet中进行调用的,获取表单的值,并且给对象赋值。

/**
     * 保存用户报修的产品信息
     * @param request
     * @param response
     * @throws IOException
     * @throws ServletException
     */
    public void saveRepairInfo(HttpServletRequest request,HttpServletResponse response) throws ServletException, IOException{
        log.info("======================进入到saveRepairInfo");

        //获取参数map集合
        Map<String, String> fieldValueMap = makeParamMap(request);

        //需要操作的类的全路径(带包名)
        String className = "com.wx.pojo.repair.RepairProduct";
        Object obj = null;

        try {
            //通过类名(类的全路径)创建Class对象
            Class<?> c = Class.forName(className);

            //通过Class对象获取类的实例
            obj = c.newInstance();
        } catch (Exception e) {
            e.printStackTrace();
        }

        //创建时间
        fieldValueMap.put("create_time", df.format(new Date()));

        //通过类的反射机制调用set方法动态给对象赋值
        ClassRefUtil.setFieldValue(obj, fieldValueMap);

        //通过强制类型转换将obj对象强转成RepairProduct类型的对象
        RepairProduct product = (RepairProduct) obj;

        //调用保存方法保存保修的信息
        boolean flag = productService.saveRepairInfo(product);

        log.info("=============保存成功标志flag:"+flag);

        if(flag){
            //设备报修信息保存之后,主动向客户推送一条报修成功的消息
            SendTemplateMsgService.sendRepairSuccessMsg(product);

            //设置页面跳转后显示的内容
            request.setAttribute("title", "报修成功!");
            request.setAttribute("msg", "您的设备信息已经报修成功,请您耐心等待,稍后我们将会在第一时间处理您的问题!您可以在我的服务记录中查看相关记录,感谢合作!!!");

            //使用ServletContext来进行页面重定向
            ServletContext sc = getServletContext();
            //保存成功之后,将跳转到成功界面
            sc.getRequestDispatcher("/mobile/feedBack.jsp").forward(request, response);
        }
    }

五,通过request.getParameterNames()方法将页面form表单中的数据获取出来并且封装成一个map键值对集合返回给调用者。这里给抽象出来形成一个单独的方法,也可以便于程序中其他的地方要用到。

/**
     * 将request.getParameterNames()方法取出的枚举参数列表转换成Map集合
     * @param params
     * @return
     */
    public Map<String, String> makeParamMap(HttpServletRequest request){
        Map<String, String> paramMap = new HashMap<String, String>();

        //读取所有可用的表单参数,该方法可以取得所有变量的名称,该方法返回一个Emumeration(枚举),键值对
        Enumeration paramNames = request.getParameterNames();

        if(null != paramNames){
            //遍历枚举
            while(paramNames.hasMoreElements()){
                String paramName = (String) paramNames.nextElement();
                String paramValue = request.getParameter(paramName);

                paramMap.put(paramName, paramValue);
            }
        }

        return paramMap;
    }

额,由于也是刚接触,所以理解的也比较浅,上面的这些只是我自己的一些理解,也不知道这样对不对,当然,反射机制属于Java中的高级应用范畴了,也是一种相当相当好的机制,我个人觉得如果理解了反射机制,也会帮助我们更好的去理解那些集成的框架,这些框架学习起来也会相对的更加的容易一些。嗯。。。慢慢进步吧!!!

时间: 2024-11-05 23:48:22

Java学习之反射机制的相关文章

Java学习:反射机制简介

反射机制是什么 反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法: 对于任意一个对象,都能够调用它的任意一个方法和属性: 这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 通俗点讲,通过反射,该类对我们来说是完全透明的,想要获取任何东西都可以. 反射机制能做什么 反射机制主要提供了以下功能: 在运行时判断任意一个对象所属的类: 在运行时构造任意一个类的对象: 在运行时判断任意一个类所具有的成员变量和方法: 在运行时调用任意一个对象的方法: 生成动

Java学习之反射机制及应用场景

前言: 最近公司正在进行业务组件化进程,其中的路由实现用到了Java的反射机制,既然用到了就想着好好学习总结一下,其实无论是之前的EventBus 2.x版本还是Retrofit.早期的View注解框架都或多或少的用到Java的反射机制.以下是自己使用反射的两个地方,感兴趣的同学可以看下:Android okHttp网络请求之Json解析,Android业务组件化之子模块SubModule的拆分以及它们之间的路由Router实现. 什么是Java反射机制? JAVA反射机制是在运行状态中,对于任

浅说Java中的反射机制(二)

写过一篇Java中的反射机制,不算是写,应该是抄了,因为那是别人写的,这一篇也是别人写的,摘抄如下: 引自于Java基础--反射机制的知识点梳理,作者醉眼识朦胧.(()为我手记) 什么是反射? 正常编译执行java文件时,会生成一个.class文件,反射就是一个反编译的过程,它可以通过.class文件得到一个java对象.一个类会有很多组成部分,比如成员变量.成员方法.构造方法等,反射可以通过加载类(加载类是个什么东西?一直搞不清楚),解剖出类的各个组成部分. 为什么要用反射? 我们需要访问一个

Java中的反射机制

Java反射的概念 Java反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为Java语言的反射机制 Java反射机制主要提供下面几种用途: 1.在运行时判断任意一个对象所属的类 2.在运行时构造任意一个类的对象 3.在运行时判断任意一个类所具有的成员变量和方法 4.在运行时调用任意一个对象的方法 首先看一个简单的例子,通过这个例子来理解Java的反射机制是如何工作的 i

java中利用反射机制绕开编译器对泛型的类型限制

首先看下面这个例子 public static void main(String[] args) { ArrayList<Integer> al1 = new ArrayList<Integer>(); al1.add(1); ArrayList<String> al2 = new ArrayList<String>(); al2.add("hello"); //int型链表和string型链表,结果为true System.out.pr

java基础篇---反射机制

一.JAVA是动态语言吗? 一般而言,说到动态言,都是指在程序运行时允许改变程序结构或者变量类型,从这个观点看,JAVA和C++一样,都不是动态语言. 但JAVA它却有着一个非常突出的动态相关机制:反射.通过反射,Java可以于运行时加载.探知和使用编译期间完全求和的类.生成其对象实体,调用其方法或者对属性设值.所以Java算是一个半动态的语言吧. 反射的概念: 在Java中的反射机制是指在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法; 对于任意一个对象,都能够调用它的任意一个方

黑马程序员——【Java高新技术】——反射机制

---------- android培训.java培训.期待与您交流! ---------- 一.概述 1.Java反射机制:是指“在运行状态中”,对于任意一个类,都能够知道这个类中的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 2.Java反射机制主要提供了以下功能: (1)在运行时,判断任意一个对象所属的类 (2)在运行时,构造任意一个类的对象 (3)在运行时,判断任意一个类所具有的成员变量和方

java基础:反射机制

一:定义 JAVA反射机制是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意一个方法和属性:这种动态获取的信息以及动态调用对象的方法的功能称为java语言的反射机制. 二:使用场景 一般用在框架的封装上.hibernate.struts都是用反射机制实现的. 举例:JDBC中加载数据库驱动Class.forName("com.mysql.jdbc.Driver"); 三:优点 反射机制的优点就是可以实现动态创建对象和编译,体现出很大的

关于JAVA中的反射机制的总结

JAVA中的反射机制是一种能够大大增强程序扩展性的技术.当一个程序封装完成后(生成exe文件),如果想要对该程序进行功能扩展,不用进行代码的从新修改(也不可能拿到源码),只要修改配置文件(一般是XML)就可以完成. 这样的程序为外部提供了一个接口,只要按照该接口的规则定义一个对象(功能),即可以为应用程序扩展该功能. 可以这样比喻,你买了一块电脑主板(封装好的程序),此时你想要添加一块声卡(要扩展的功能),此时只能够通过一个pci接口(应用程序提供的接口)来进行扩展.声卡的接口必须符合PCI的规