Java学习之反射机制

来源:互联网 发布:夏普网络扫描仪工具 编辑:程序博客网 时间:2024/05/23 11:41

前段时间在做项目的时候,由于是用的纯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中的高级应用范畴了,也是一种相当相当好的机制,我个人觉得如果理解了反射机制,也会帮助我们更好的去理解那些集成的框架,这些框架学习起来也会相对的更加的容易一些。嗯。。。慢慢进步吧!!!

0 0
原创粉丝点击