进阶Java编程(10)反射与简单Java类

1,传统属性自动赋值弊端

  简单Java类主要由属性构成,而且提供有setter与getter类,同时简单Java类最大的特征就是经过对象保存相应的类属性的内容。可是若是使用传统的简单Java类开发,那么也会面临很是麻烦的困难。java

  ·范例:传统的简单Java类操做编程

1 package cn.demo11.demo; 2 class Emp{ 3 private String ename; 4 private String job; 5 //setter、getter略 6 }

  特别强调,为了方便理解,本次Emp类之中定义的ename、job两个属性都是使用String类型。按照传统的作法此时应该首先实例化Emp类的对象,然后经过实例化对象进行setter方法的调用以设置内容。工具

  ·范例:传统的调用spa

1     public static void main(String[] args) { 2 Emp emp=new Emp(); 3 emp.setEname("万雨"); 4 emp.setJob("Java开发工程师"); 5 System.out.print("姓名:"+emp.getEname()+",职位:"+emp.getJob()); 6  } 7 } 8 /*输出 9 姓名:万雨,职位:Java开发工程师 10 */ 11 

  在整个进行Emp对象实例化并设置数据的操做过程之中,设置数据的部分是最麻烦的,你能够想象一下,若是Emp类里面提供有50个属性,那么对于整个程序将会成为一堆的setter方法的调用。或者再进一步说明,在实际开发之中,简单Java类的个数是很是多的,那么若是全部的简单Java列都牵扯到属性的赋值的时候,这种状况下代码编写的重复性将会很是高!!!设计

  按照传统的直观的编程方法,所带来的问题就是代码会存在有大量的重复操做,若是想要解决对象的重复处理操做那么惟一的解决方案就是【反射机制】,反射机制最大的特定就是能够根据自身的特色【Object类直接操做、能够直接操做属性和方法】实现相同功能类的重复操做的抽象处理。code

2,属性自动赋值实现思路

  通过分析以后已经确认了当前简单Java类操做的问题所在,而对于开发这而言就须要想办法经过一种解决方案来实现属性内容的自动设置,那么这个时候设置强烈建议采用字符串的形式描述对应的类型。orm

  ①在进行程序开发的时候String字符串能够描述的内容有不少,而且也能够由开发者自行定义字符串的结构,下面就采用【属性:内容|属性:内容】的形式来为简单Java类进行赋值对象

  ②类设计的基本结构:应该由一个专门的ClassInstanceFactory类负责全部的反射处理,即:接收反射对象与要设置的属性内容同时能够获取指定类的实例化对象。blog

  ③设计的基本结构:开发

1 class ClassInstanceFactory{ 2 private ClassInstanceFactory(){}//无参构造 3 /** 4 * 实例化对象的建立方法,该对象能够根据传入的字符串结构【属性:内容|属性:内容】 5 * @param clazz 要进行反射实例化的Class类对象,有Class就能够反射实例化对象 6 * @param value 要设置给对象的属性内容 7 * @param <T> 8 * @return 一个已经配置好属性内容的简单Java类对象 9 */ 10 public static <T> T create(Class<?> clazz,String value){ 11 return null; 12  } 13 }

  那么在当前的开发之中,所须要留给用户完善的就是ClassInstanceFactory.create()处理方法。

3,单级属性配置

  对于此时的Emp类里面会发现所给出的数据类型都没其余的引用关联了,只是描述了Emp本类的对象,因此这样的设置称为单级设置处理,因此此时应该处理两件事情:

  ①须要经过反射进行指定类对象的实例化处理;

  ②进行内容的设置(Field属性类型,方法名称、要设置的内容);

  ①定义StringUtils实现首字母大写功能

1 package cn.demo13.demo; 2 3 class StringUtils { 4 public static String initcap(String str){ 5 if(str==null||"".equals(str)){ 6 return str; 7  } 8 if(str.length()==1){ 9 return str.toUpperCase(); 10 }else{ 11 return str.substring(0,1).toUpperCase()+str.substring(1); 12  } 13  } 14 }

  ②定义BeanUtils工具类,该工具类主要实现属性的设置

1 package cn.demo13.demo; 2 3 import java.lang.reflect.Field; 4 import java.lang.reflect.Method; 5 6 public class BeanUtils {//进行Bean处理类 7 private BeanUtils(){} 8 /** 9 * 实现指定对象的属性设置 10 * @param obj 要进行反射操做的实例化对象 11 * @param value 包含有指定内容的字符串,格式【属性:内容|属性:内容】 12 */ 13 public static void setValue(Object obj,String value) { 14 String[] results=value.split("\\|");//字符串拆分 15 for(int x=0;x<results.length;x++){ 16 //attval[0]保存的是属性的名称、attval[1]保存的是属性内容 17 String[] attval=results[x].split(":");//获取【属性名称】与【内容】 18 try{ 19 Field field=obj.getClass().getDeclaredField(attval[0]);//获取属性成员 20 Method setMethod=obj.getClass().getDeclaredMethod("set"+StringUtils.initcap(attval[0]),field.getType()); 21 setMethod.invoke(obj,attval[1]);//调用setter方法设置内容 22 }catch (Exception e){ 23  e.printStackTrace(); 24  } 25 26  } 27  } 28 }

  ③ClassInstanceFactroy负责实例化对象而且调用BeanUtils类实现属性内容的设置

1 package cn.demo13.demo; 2 3 class ClassInstanceFactory{ 4 private ClassInstanceFactory(){} 5 public static <T> T create(Class<?> clazz,String value){ 6 try{//若是想要采用反射进行简单Java类对象属性的设置,类中必需要有无参构造 7 Object obj=clazz.getDeclaredConstructor().newInstance(); 8 BeanUtils.setValue(obj,value);//经过反射设置属性 9 return (T) obj; 10 }catch (Exception e){ 11 e.printStackTrace();//即使出现错误也不影响后续代码的执行 12 return null; 13  } 14  } 15 }

4,设置多种数据类型

  如今已经成功的实现了单级的属性配置,可是这里面依然须要考虑一个实际的状况,咱们当前所给定的数据类型只是String,可是在实际的开发之中面对简单Java类中的属性类型通常的可选方案为:long(Long)、int(Integer)、double(Double)、String、Date(日期或者日期时间),因此对于当前的程序代码而言就必须作出修改,能够实现各类数据的类型的配置。

  既然要求能够实现不一样类型的内容的设置,而且BeanUtils类主要是完成属性赋值处理的,那么就能够在这个类之中追加有一些列的处理方法。

 1 package cn.demo13.demo;  2 
 3 import java.lang.reflect.Field;  4 import java.lang.reflect.Method;  5 import java.text.ParseException;  6 import java.text.SimpleDateFormat;  7 import java.util.Date;  8 
 9 public class BeanUtils {//进行Bean处理类
10     private BeanUtils(){} 11     /**
12  * 实现指定对象的属性设置 13  * @param obj 要进行反射操做的实例化对象 14  * @param value 包含有指定内容的字符串,格式【属性:内容|属性:内容】 15      */
16     public static void setValue(Object obj,String value) { 17         String[] results=value.split("\\|");//字符串拆分
18         for(int x=0;x<results.length;x++){ 19             //attval[0]保存的是属性的名称、attval[1]保存的是属性内容
20             String[] attval=results[x].split(":");//获取【属性名称】与【内容】
21 
22             try{ 23                 Field field=obj.getClass().getDeclaredField(attval[0]);//获取属性成员
24                 Method setMethod=obj.getClass().getDeclaredMethod("set"+StringUtils.initcap(attval[0]),field.getType()); 25                 Object convertVal=BeanUtils.convertAttributeValue(field.getType().getName(),attval[1]); 26                 setMethod.invoke(obj,convertVal);//调用setter方法设置内容
27             }catch (Exception e){ 28  e.printStackTrace(); 29  } 30 
31  } 32  } 33 
34     /**
35  * 实现属性类型转换处理 36  * @param type 属性类型,经过Field获取 37  * @param value 属性的内容,传入的都是字符串,须要将其变为指定类型 38  * @return 转换后的数据 39      */
40     private static Object convertAttributeValue(String type,String value){ 41 // System.out.println("type="+type+",value="+value);
42         if("long".equals(type)||"java.lang.Long".equals(type)){//长整型
43             return Long.parseLong(value); 44         }else if("int".equals(type)||"java.lang.int".equals(type)){ 45             return Integer.parseInt(value); 46         }else if("double".equals(type)||"java.lang.double".equals(type)){ 47             return Double.parseDouble(value); 48         }else if("java.util.Date".equals(type)){ 49 
50             SimpleDateFormat sdf=null; 51             if(value.matches("\\d{4}-\\d{2}-\\d{2}")){//日期类型
52                 sdf=new SimpleDateFormat("yyyy-MM-dd"); 53             }else if(value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")){//有日期
54                 sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 55             }else { 56                 return new Date(); 57  } 58             try { 59                 return sdf.parse(value); 60             } catch (ParseException e) { 61                 return new Date(); 62  } 63         }else { 64             return value; 65  } 66  } 67 }

  此时只是列举出了几种常见的数据类型,若是想要将其做为一个产品推广,那么就必需要考虑全部可能出现的类型,同时全部可能的日期格式也须要考虑。

5,级联对象实例化

  若是说给定的类对象之中存在其余的引用的级联关系的状况下,称为多级设置。例如:一个雇员属于一个部门,一个部门属于一个公司,因此这个时候对于简单Java类的基本关系定义以下:

  初始化3个类:Emp、Company、Dept。

public class Emp { private String ename; private String job; private long empno; private double salary; private Date hiredate; private Dept dept;//setter、getter略
}
1 public class Company { 2     private String name; 3     private Date createDate;//setter、getter略
4 }
1 public class Dept { 2     private String dname; 3     private String loc; 4     private Company company;//setter、getter略
5 }

  若是要经过Emp进行操做,则应该使用【.】做为级联关系的处理:

dept.dname:财务部——>Emp的实例化对象.getDept().setDname("财务部");

dept.company.name:Mufasa——>Emp的实例化对象.getDpet().getCompany().setName("Mufasa");

  考虑到代码的简洁性,因此应该考虑能够经过级联的配置自动实现类中属性的实例化

1     String value="ename:万雨|empno:7369|job:Java开发工程师|salary:750.00|hiredate:1989-10-10|"
2             +"dept.dname:财务部|dept.company.name:Mufasa";

  如今的属性存在多级关系,那么多级的关系就必须与单级的配置区分开。

 1 package com.company.mufasa;  2 
 3 import java.lang.reflect.Field;  4 import java.lang.reflect.Method;  5 import java.text.ParseException;  6 import java.text.SimpleDateFormat;  7 import java.util.Arrays;  8 import java.util.Date;  9 
10 public class BeanUtils {//进行Bean处理类
11     private BeanUtils(){} 12     /**
13  * 实现指定对象的属性设置 14  * @param obj 要进行反射操做的实例化对象 15  * @param value 包含有指定内容的字符串,格式【属性:内容|属性:内容】 16      */
17     public static void setValue(Object obj,String value) { 18         String[] results=value.split("\\|");//字符串拆分
19         for(int x=0;x<results.length;x++){ 20             //attval[0]保存的是属性的名称、attval[1]保存的是属性内容
21             String[] attval=results[x].split(":");//获取【属性名称】与【内容】
22 
23             try{ 24                 if(attval[0].contains(".")){//多级配置
25                     String[] temp=attval[0].split("\\."); 26                     Object currentObject=obj; 27                     //最后一位确定是类中的属性名称,因此不在本次实例化处理的范畴以内
28                     for (int y=0;y<temp.length-1;y++){//实例化 29                         //调用相应的getter方法,若是getter方法返回了null表示该对象为实例化
30                         Method getMethod=currentObject.getClass().getDeclaredMethod("get"+StringUtils.initcap(temp[y])); 31                         Object tempObject=getMethod.invoke(currentObject); 32                         if(tempObject==null){//该对象没有实例化
33                             Field field=currentObject.getClass().getDeclaredField(temp[y]);//获取属性类型
34                             Method method=currentObject.getClass().getDeclaredMethod("set"+StringUtils.initcap(temp[y]),field.getType()); 35                             Object newObject=field.getType().getDeclaredConstructor().newInstance(); 36  method.invoke(currentObject,newObject); 37                             currentObject=newObject; 38                         }else { 39                             currentObject=tempObject; 40  } 41 // System.out.println(temp[y]+"----"+currentObject);
42  } 43 
44 
45                 }else {//单级配置
46                     Field field=obj.getClass().getDeclaredField(attval[0]);//获取属性成员
47                     Method setMethod=obj.getClass().getDeclaredMethod("set"+StringUtils.initcap(attval[0]),field.getType()); 48                     Object convertVal=BeanUtils.convertAttributeValue(field.getType().getName(),attval[1]); 49                     setMethod.invoke(obj,convertVal);//调用setter方法设置内容
50  } 51 
52             }catch (Exception e){ 53  e.printStackTrace(); 54  } 55 
56  } 57  } 58 
59     /**
60  * 实现属性类型转换处理 61  * @param type 属性类型,经过Field获取 62  * @param value 属性的内容,传入的都是字符串,须要将其变为指定类型 63  * @return 转换后的数据 64      */
65     private static Object convertAttributeValue(String type,String value){ 66 // System.out.println("type="+type+",value="+value);
67         if("long".equals(type)||"java.lang.Long".equals(type)){//长整型
68             return Long.parseLong(value); 69         }else if("int".equals(type)||"java.lang.int".equals(type)){ 70             return Integer.parseInt(value); 71         }else if("double".equals(type)||"java.lang.double".equals(type)){ 72             return Double.parseDouble(value); 73         }else if("java.util.Date".equals(type)){ 74 
75             SimpleDateFormat sdf=null; 76             if(value.matches("\\d{4}-\\d{2}-\\d{2}")){//日期类型
77                 sdf=new SimpleDateFormat("yyyy-MM-dd"); 78             }else if(value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")){//有日期
79                 sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 80             }else { 81                 return new Date(); 82  } 83             try { 84                 return sdf.parse(value); 85             } catch (ParseException e) { 86                 return new Date(); 87  } 88         }else { 89             return value; 90  } 91  } 92 }

  这些自动的级联配置的实例化处理操做,在之后进行项目的编写之中必定会使用到。

6,级联属性赋值

   如今已经实现级联的实例化处理,随后要解决级联的属性设置问题。在进行级联实例化处理的时候循环都是少了一位的。

 1 for (int y=0;y<temp.length-1;y++){//实例化  2         //调用相应的getter方法,若是getter方法返回了null表示该对象为实例化
 3         Method getMethod=currentObject.getClass().getDeclaredMethod("get"+StringUtils.initcap(temp[y]));  4         Object tempObject=getMethod.invoke(currentObject);  5         if(tempObject==null){//该对象没有实例化
 6         Field field=currentObject.getClass().getDeclaredField(temp[y]);//获取属性类型
 7         Method method=currentObject.getClass().getDeclaredMethod("set"+StringUtils.initcap(temp[y]),field.getType());  8         Object newObject=field.getType().getDeclaredConstructor().newInstance();  9  method.invoke(currentObject,newObject); 10         currentObject=newObject; 11         }else { 12         currentObject=tempObject; 13  } 14  } 15 }

  当此时代码循环处理完成以后,currentObject表示的就是能够进行setter方法调用的对象了,而且理论上该对象必定不可能为null,随后就能够按照以前的方式利用对象进行setter调用。

  ·范例:实现对象的级联属性设置

 

 1 package com.company.mufasa;  2 
 3 import java.lang.reflect.Field;  4 import java.lang.reflect.Method;  5 import java.text.ParseException;  6 import java.text.SimpleDateFormat;  7 import java.util.Arrays;  8 import java.util.Date;  9 
10 public class BeanUtils {//进行Bean处理类
11     private BeanUtils(){} 12     /**
13  * 实现指定对象的属性设置 14  * @param obj 要进行反射操做的实例化对象 15  * @param value 包含有指定内容的字符串,格式【属性:内容|属性:内容】 16      */
17     public static void setValue(Object obj,String value) { 18         String[] results=value.split("\\|");//字符串拆分
19         for(int x=0;x<results.length;x++){ 20             //attval[0]保存的是属性的名称、attval[1]保存的是属性内容
21             String[] attval=results[x].split(":");//获取【属性名称】与【内容】
22 
23             try{ 24                 if(attval[0].contains(".")){//多级配置
25                     String[] temp=attval[0].split("\\."); 26                     Object currentObject=obj; 27                     //最后一位确定是类中的属性名称,因此不在本次实例化处理的范畴以内
28                     for (int y=0;y<temp.length-1;y++){//实例化 29                         //调用相应的getter方法,若是getter方法返回了null表示该对象为实例化
30                         Method getMethod=currentObject.getClass().getDeclaredMethod("get"+StringUtils.initcap(temp[y])); 31                         Object tempObject=getMethod.invoke(currentObject); 32                         if(tempObject==null){//该对象没有实例化
33                             Field field=currentObject.getClass().getDeclaredField(temp[y]);//获取属性类型
34                             Method method=currentObject.getClass().getDeclaredMethod("set"+StringUtils.initcap(temp[y]),field.getType()); 35                             Object newObject=field.getType().getDeclaredConstructor().newInstance(); 36  method.invoke(currentObject,newObject); 37                             currentObject=newObject; 38                         }else { 39                             currentObject=tempObject; 40  } 41 
42  } 43                     Field field=currentObject.getClass().getDeclaredField(temp[temp.length-1]);//获取成员
44                     Method setMethod=currentObject.getClass().getDeclaredMethod("set"+StringUtils.initcap(temp[temp.length-1]),field.getType()); 45                     Object convertVal=BeanUtils.convertAttributeValue(field.getType().getName(),attval[1]); 46                     setMethod.invoke(currentObject,convertVal);//调用setter方法设置内容
47                 }else {//单级配置
48                     Field field=obj.getClass().getDeclaredField(attval[0]);//获取属性成员
49                     Method setMethod=obj.getClass().getDeclaredMethod("set"+StringUtils.initcap(attval[0]),field.getType()); 50                     Object convertVal=BeanUtils.convertAttributeValue(field.getType().getName(),attval[1]); 51                     setMethod.invoke(obj,convertVal);//调用setter方法设置内容
52  } 53 
54             }catch (Exception e){ 55  e.printStackTrace(); 56  } 57 
58  } 59  } 60 
61     /**
62  * 实现属性类型转换处理 63  * @param type 属性类型,经过Field获取 64  * @param value 属性的内容,传入的都是字符串,须要将其变为指定类型 65  * @return 转换后的数据 66      */
67     private static Object convertAttributeValue(String type,String value){ 68 // System.out.println("type="+type+",value="+value);
69         if("long".equals(type)||"java.lang.Long".equals(type)){//长整型
70             return Long.parseLong(value); 71         }else if("int".equals(type)||"java.lang.int".equals(type)){ 72             return Integer.parseInt(value); 73         }else if("double".equals(type)||"java.lang.double".equals(type)){ 74             return Double.parseDouble(value); 75         }else if("java.util.Date".equals(type)){ 76 
77             SimpleDateFormat sdf=null; 78             if(value.matches("\\d{4}-\\d{2}-\\d{2}")){//日期类型
79                 sdf=new SimpleDateFormat("yyyy-MM-dd"); 80             }else if(value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")){//有日期
81                 sdf=new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); 82             }else { 83                 return new Date(); 84  } 85             try { 86                 return sdf.parse(value); 87             } catch (ParseException e) { 88                 return new Date(); 89  } 90         }else { 91             return value; 92  } 93  } 94 }

  在之后的简单Java类之中简单Java类的幅值将再也不重复调用setter方法操做完成,而这种处理形式是在正轨开发中广泛采用的方式。

相关文章
相关标签/搜索