假设现在我们有一个POJO(Plain ordinary Java Object),要实现它的setter操作,一般来说我们是这么写的,我先举个例子。
class ClassA{ private int a; private int b; private int c; public void setA(int a) { this.a = a; } public void setB(int b) { this.b = b; } public void setC(int c) { this.c = c; } @Override public String toString() { return (this.a+this.b+this.c)+" "; } }
这个POJO中只有三个私有变量,假设我们只有默认的无参构造,那么当我们设置ClassA的属性的时候就要调用三次set方法。假设我们有100个变量,那么我们要设置好属性就必须调用100次set方法。那么属性再多一些的话就凉凉了。
我们其实可以对程序做很好的优化,假设我们可以通过输入一个长字符串来一次性设置好一个类对象中的所有属性。我们可以通过反射来很好的解决这个问题。
假设我们输入“Person.name:张三|Person.age:20”就可以实现把Person类的对象中的name和age设置成张三和20。那么,程序设计的第一步就是先创建一个Person类
import java.lang.reflect.Field; import java.lang.reflect.Method; class Person{//Person类(POJO) private String name; private String age; public void setName(String name) { this.name = name; } public void setAge(String age) { this.age = age; } @Override public String toString() {//覆写toString() return "name: "+this.name+" age: "+this.age; } }
我们指定的字符串假设就是上面的那种类型“Person.name:张三|Person.age:20”,在考虑怎么设置属性之前,我们需要考虑的问题是:假设有一个别的类,类中有别的属性,就像这样“Student.name:李四|Student.grade:two|Student.sex:man|......”。形式和原来的一样,就是Class对象和属性变了。那么我们的代码是不是应该要有大幅度的改动呢,我们为了防止出现这种情况。我门可以这么来设计:创建一个新的类,这个类创建字符串里的Class对象,并且这个类中通过调用一些工具方法来实现对Class对象属性的赋值。那么,当Class对象因为我们输入的字符串而改变的时候,我们只需要修改这个类中创建的Class对象和Class对象的POJO就可以了。这种设计方法可以省去很多多余的代码。
/** * 当Class对象改变时只需要修改此类便可以实现 * 和原来同样的效果 */ class PersonAction{//Person类对象实例的创建与属性设置类 private Person person = new Person();//方法里私有化创建一个Class对象 public void setvalue(String value)throws Exception {//通过调用工具类的方法来设置属性 BeanOperation.setValue(this,value); } public Person getPerson() {//当Class对象改变时我们只需要修改这里 return person; } }
接下来就是重点:如何通过字符串来给对象中的属性赋值?其实我们可以通过字符串的拆分(split()方法)来获取字符串中提供的Class对象信息,属性名,属性值。这些工作可以做成静态的工具方法让我们以便我们使用。我们来理一下步骤:
1:先拆分字符串,提取信息。
/** * 工具类 * 通过对字符串的信息提取实现VO匹配处理 * */ class BeanOperation {//工具类 private BeanOperation(){}//工具类的构造私有化 public static void setValue(Object obj, String value)throws Exception {//进行拆分字符串并提取信息 String[] result = value.split("\\|");//拆开字符串 for(int i = 0;i < result.length;i++) { String[] strings = result[i].split(":"); String ClassName = strings[0].split("\\.")[0];//类名 String FieldName = strings[0].split("\\.")[1];//属性名 String Fielddata = strings[1];//属性值 Object RealObject = GetRealObject(obj, ClassName);//通过字符串内的Class对象名拿到 // PersonAction类中getPerson提供的Person对象 setRealObjectValue(RealObject,FieldName,Fielddata);//调用对象的set方法来设置属性 } }
创建工具类来存放我们所需要的静态工具方法,把工具类的构造私有化。这个工具方法主要是进行字符串的拆分,提取信息,以及通过提取到的Class对象名来通过反射拿到PersonAction类里的私有Class对象。既然拿到了对象,那么就可以继续通过反射来调用对象里的set()方法来设置属性了。
这里所接受的参数:Object obj:PersonAction对象。String value:要设置属性而由用户提供的字符串。
2:通过字符串中Class对象的信息,通过反射拿到PersonAction类中的Person实例化对象。
public static Object GetRealObject(Object object, String ClassName) throws Exception {//此方法取得真正的Person类对象 Class<?> cls = object.getClass(); Field field = cls.getDeclaredField(ClassName);//首先看下 PersonAction类中有没有Person对象 if (field == null) {//本类中没有 field = cls.getField(ClassName);//在父类中找找看 if (field == null) { return null;//如果不存在Person对象就凉凉,直接返回null } } String methodname = "get" + initCap(ClassName);//拿到了getPerson的方法名 Method method = cls.getDeclaredMethod(methodname);//找到了getPerson方法 return method.invoke(object);//把PersonAction中已经实例化的Person对象返回(调用了其中的getPerson方法) }
这个方法的参数:Object object:PersonAction类对象。String ClassName:从字符串中提取的Class对象(Person)。
这个工具方法里都是反射,首先检测PersonAction类中有没有Person类的对象,如果连对象都没有就直接返回了。如果有的话,我们要先拿到getClass的方法名(getPerson)。这里我们就要用到从字符串中提取到的Class对象名了(Person)。拿到方法名之后就找到并调用它,注意调用它的对象是PersonAction。这样我们就拿到PersonAction里的Person对象了。然后返回就可以了,因为我们还要用这个对象来调用set方法。
3.用返回的Class(Person)对象调用set方法。
public static void setRealObjectValue(Object obj,String FieldName,String FieldValue)throws Exception{//设置属性的工具方法 Field field = obj.getClass().getDeclaredField(FieldName);//看看Person对象里有没有叫做FieldName的属性 if(field == null){ field = obj.getClass().getField(FieldName);//没有的话在父类里找找 if(field == null){ return;//找不到就返回 } } String MethodName = "set"+initCap(FieldName);//拿到set方法的名字 Method setmethod = obj.getClass().getMethod(MethodName,field.getType());//拿到set方法 setmethod.invoke(obj,FieldValue);//相当于调用Person中的set方法 }
参数:Object obj:拿到的Class对象。String FieldName:字符串拆出来的属性名。String FieldValue:提取出的属性值
本质上和第二步差不多,首先检测Class对象里是否存在叫做FieldName的属性,没有就返回,有的话就通过属性名永反射拿到set方法的名字并且调用。就相当于调用了Person中的set方法。
通过这三步,Person对象中的属性就会被初始化完毕。我先上完整的代码。
import java.lang.reflect.Field; import java.lang.reflect.Method; class Person{//Person类(POJO) private String name; private String age; public void setName(String name) { this.name = name; } public void setAge(String age) { this.age = age; } @Override public String toString() { return "name: "+this.name+" age: "+this.age; } } /** * 当Class对象改变时只需要修改此类便可以实现 * 和原来同样的效果 */ class PersonAction{//Person类对象实例的创建与属性设置类 private Person person = new Person(); public void setvalue(String value)throws Exception {//通过调用工具类的方法来设置属性 BeanOperation.setValue(this,value); } public Person getPerson() { return person; } } /** * 工具类 * 通过对字符串的信息提取实现VO匹配处理 * */ class BeanOperation {//工具类 private BeanOperation(){}//工具类的构造私有化 public static void setValue(Object obj, String value)throws Exception {//进行拆分字符串并提取信息 String[] result = value.split("\\|");//拆开字符串 for(int i = 0;i < result.length;i++) { String[] strings = result[i].split(":"); String ClassName = strings[0].split("\\.")[0];//类名 String FieldName = strings[0].split("\\.")[1];//属性名 String Fielddata = strings[1];//属性值 Object RealObject = GetRealObject(obj, ClassName);//通过字符串内的Class对象名拿到 // PersonAction类中getPerson提供的Person对象 setRealObjectValue(RealObject,FieldName,Fielddata);//调用对象的set方法来设置属性 } } public static Object GetRealObject(Object object, String ClassName) throws Exception {//此方法取得真正的Person类对象 Class<?> cls = object.getClass(); Field field = cls.getDeclaredField(ClassName);//首先看下 PersonAction类中有没有Person对象 if (field == null) {//本类中没有 field = cls.getField(ClassName);//在父类中找找看 if (field == null) { return null;//如果不存在Person对象就凉凉,直接返回null } } String methodname = "get" + initCap(ClassName);//拿到了getPerson的方法名 Method method = cls.getDeclaredMethod(methodname);//找到了getPerson方法 return method.invoke(object);//把PersonAction中已经实例化的Person对象返回(调用了其中的getPerson方法) } public static String initCap(String ClassName){//将属性名首字母大写 return ClassName.substring(0,1).toUpperCase()+ClassName.substring(1); } public static void setRealObjectValue(Object obj,String FieldName,String FieldValue)throws Exception{//设置属性的工具方法 Field field = obj.getClass().getDeclaredField(FieldName);//看看Person对象里有没有叫做FieldName的属性 if(field == null){ field = obj.getClass().getField(FieldName);//没有的话在父类里找找 if(field == null){ return;//找不到就返回 } } String MethodName = "set"+initCap(FieldName);//拿到set方法的名字 Method setmethod = obj.getClass().getMethod(MethodName,field.getType());//拿到set方法 setmethod.invoke(obj,FieldValue);//相当于调用Person中的set方法 } } public class Main{//测试 public static void main(String[] args)throws Exception{ String string = "person.name:dangxinyu|person.age:20"; PersonAction personAction = new PersonAction();//Person类的"管理"类 personAction.setvalue(string);//通过字符串给personAction中的Person类对象赋值 System.out.println(personAction.getPerson());//打印personAction中的Person属性 } }
我输入的字符串是“Person.name:dangxinyu|Person.age:20”。赋值成功。
这就是单级VO设置属性的过程,希望能对大家有所帮助