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中的高级应用范畴了,也是一种相当相当好的机制,我个人觉得如果理解了反射机制,也会帮助我们更好的去理解那些集成的框架,这些框架学习起来也会相对的更加的容易一些。嗯。。。慢慢进步吧!!!
- java学习之反射机制
- Java学习之-----反射机制
- java学习之反射机制
- Java学习之反射机制
- Java学习之反射机制
- Java学习之反射机制
- Java学习之二-Java反射机制
- Java学习之二-Java反射机制
- Java学习之二-Java反射机制
- Java学习之二-Java反射机制
- java学习之理解反射机制
- Java学习笔记之反射机制初探
- Java学习之反射机制笔记--4
- Java学习之反射机制---动态代理
- java学习笔记之反射机制
- Java学习笔记之反射机制
- java反射机制学习
- JAVA反射机制学习
- VC++项目中firebreath生成的代码中如何加入jsoncpp库
- 机器学习算法基础概念学习总结
- 有趣的Java 8
- Silverlight中用户直接退出浏览器时如何判断用户离线
- itextpdf输出PDF笔记
- Java学习之反射机制
- Climbing Stairs
- 怎样读一篇论文
- js实现div弹框和关闭
- UML之状态图
- Thread - JConsole
- php导出excel
- Spring4.0使用websocke遇到的一些问题
- 孙鑫 VC++深入详解——学习笔记