属性自动设置
属性设置建议采用字符串的形式来描述对应的类型。
1、采用“属性:内容|属性:内容|”的形式来为简单Java类中的属性初始化。
2、类设计的基本结构:应该由一个专门的ClassInstanceFactory类负责所有的反射处理,即:接收反射对象与要设置的反射内容,同时可以获取指定类的实例化对象
3、设计的基本结构:
package demo;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
String value = "ename:Smithi|job:Clerk" ;
Emp emp = ClassInstanceFactory.create(Emp.class, value);
System.out.println("姓名:" + emp.getEname() + "、职位:" + emp.getJob());
}
}
class ClassInstanceFactory{
private ClassInstanceFactory() {}
/**
* 实例化对象的创建方法,该对象可以根据传入的字符串结构“属性:内容|属性:内容”
* @param <T>
* @param clazz 要进行反射实例化的Class类对象,有Class就可以反射实例化对象
* @param value 要设置给对象的属性内容
* @return 一个已经配置好属性内容的Java类对象
*/
public static <T> T create(Class<?> clazz, String value) {
return null;
}
}
class Emp{
private String ename;
private String job;
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
}
要留给用户完善的就是ClassInstanceFactory.create()处理方法。
单级属性配置
对于此时的Emp类里面会发现所给出的数据类都没有其它的引用关联了,至少描述了Emp的本类的对象,这样的设置称为单级设置处理,所以此时应该处理两件事:
- 需要通过反射进行指定类对象的实例化处理;
- 进行内容的设置(Field属性类型、方法名称、要设置的内容);
1、定义String类实现首字母大写
class StringUtils{
public static String initcap(String str) {
if(str == null || "".equals(str)) {
return str;
}
if(str.length()==1) {
return str.toUpperCase();
}else {
return str.substring(0,1).toUpperCase() + str.substring(1);
}
}
}
2、定义BeanUtils工具类,该工具类主要实现属性的设置。
class BeanUtils{
private BeanUtils() {}
/**
* 实现指定对象的属性设置
* @param obj 要进行反射操作的实例化对象
* @param value 包含有指定内容的字符串,格式“属性:内容|属性:内容”
*/
public static void setValue(Object obj, String value) {
String results [] = value.split("\\|");//按照“|”进行分组拆分
for(int x=0; x< results.length;x++) {//循环设置属性内容
//attval[0]保存的是属性名称、attval[1]保存的是属性内容
String attval[] = results[x].split(":");//获取“属性名称”与内容
try {
Field field = obj.getClass().getDeclaredField(attval[0]);//获取成员
Method setMethod = obj.getClass().getDeclaredMethod("set"+StringUtils.initcap(attval[0]), field.getType());
setMethod.invoke(obj, attval[1]);//调用setter 方法设置内容
}catch(Exception e) {
}
}
}
}
3、ClassInstanceFactory负责实例化对象并且调用BeanUtils类实现属性内容的设置。
class ClassInstanceFactory{
private ClassInstanceFactory() {}
/**
* 实例化对象的创建方法,该对象可以根据传入的字符串结构“属性:内容|属性:内容”
* @param <T>
* @param clazz 要进行反射实例化的Class类对象,有Class就可以反射实例化对象
* @param value 要设置给对象的属性内容
* @return 一个已经配置好属性内容的Java类对象
*/
public static <T> T create(Class<?> clazz, String value) {
//如果要想采用反射机型简单Java类对象属性设置的时候,类中必须要有无参构造
try {
Object obj = clazz.getDeclaredConstructor().newInstance();
BeanUtils.setValue(obj, value);//通过反射设置属性
return (T) obj;//返回对象
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
即使现在类中的属性再多,那么也可以轻松实现setter的调用(类对象实例化处理)
设置多种数据类型
在一般的实际开发之中面对java类中的属性类型一般可选为:long(Long)、int(Integer)、double(Double)、String、Date(日期、日期时间),所以当前的程序代码就必须做出修改,要求可以实现各种数据类型的配置。
package demo;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
String value = "empno:940525|ename:Smithi|job:Clerk|salary:9999.88|hiredate:1994-05-25" ;
Emp emp = ClassInstanceFactory.create(Emp.class, value);
System.out.println("工号:"+emp.getEmpno()+"姓名:" + emp.getEname() + "、职位:" + emp.getJob()+"、薪水:" + emp.getSalary()+"、雇佣日期:" + emp.getHiredate());
}
}
class ClassInstanceFactory{
private ClassInstanceFactory() {}
/**
* 实例化对象的创建方法,该对象可以根据传入的字符串结构“属性:内容|属性:内容”
* @param <T>
* @param clazz 要进行反射实例化的Class类对象,有Class就可以反射实例化对象
* @param value 要设置给对象的属性内容
* @return 一个已经配置好属性内容的Java类对象
*/
public static <T> T create(Class<?> clazz, String value) {
//如果要想采用反射机型简单Java类对象属性设置的时候,类中必须要有无参构造
try {
Object obj = clazz.getDeclaredConstructor().newInstance();
BeanUtils.setValue(obj, value);//通过反射设置属性
return (T) obj;//返回对象
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
class StringUtils{
public static String initcap(String str) {
if(str == null || "".equals(str)) {
return str;
}
if(str.length()==1) {
return str.toUpperCase();
}else {
return str.substring(0,1).toUpperCase() + str.substring(1);
}
}
}
class BeanUtils{
private BeanUtils() {}
/**
* 实现指定对象的属性设置
* @param obj 要进行反射操作的实例化对象
* @param value 包含有指定内容的字符串,格式“属性:内容|属性:内容”
*/
public static void setValue(Object obj, String value) {
String results [] = value.split("\\|");//按照“|”进行分组拆分
for(int x=0; x< results.length;x++) {//循环设置属性内容
//attval[0]保存的是属性名称、attval[1]保存的是属性内容
String attval[] = results[x].split(":");//获取“属性名称”与内容
try {
Field field = obj.getClass().getDeclaredField(attval[0]);//获取成员
Method setMethod = obj.getClass().getDeclaredMethod("set"+StringUtils.initcap(attval[0]), field.getType());
Object convertValue = BeanUtils.convertAttributeValue(field.getType().getName(), attval[1]);
setMethod.invoke(obj, convertValue);//调用setter 方法设置内容
}catch(Exception e) {
}
}
}
/**
* 实现属性类型转换处理
* @param type 属性类型,通过Field获取
* @param value 属性 的内容,传入的都是字符串,需要将其转变为指定类型
* @return 转换后的数据
*/
private static Object convertAttributeValue(String type,String value) {
// System.out.println("type =" + type + "、value=" + value);
if("long".equals(type)|| "java.lang.Long".equals(type)) {
return Long.parseLong(value);
}else if("int".equals(type)||"java.lang.int".equals(type)) {
return Integer.parseInt(value);
}else if("double".equals(type)||"java.lang.double".equals(type)) {
return Double.parseDouble(value);
}else if("java.util.Date".equals(type)) {
SimpleDateFormat sdf = null;
if(value.matches("\\d{4}-\\d{2}-\\d{2}")) {
sdf = new SimpleDateFormat("yyyy-MM-dd");
}else if(value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) {
sdf = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss");
}else {
return new Date();//当前日期
}
try {
return sdf.parse(value);
}catch(ParseException e){
return new Date();
}
}else {
return value;
}
}
}
class Emp{
private long empno;
private String ename;
private String job;
private double salary;
private Date hiredate;
public String getEname() {
return ename;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Long getEmpno() {
return empno;
}
public void setEmpno(long empno) {
this.empno = empno;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
}
级联对象实例化
在给定的类对象之中存在有其它的引用的级联关系的情况下,成为多级设置。例如:一个雇员属于一个部门,一个部门属于一个公司。所以这时候简单Java类的级联关系如下:
class Company{
private String name;
private Date createdate;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreatedate() {
return createdate;
}
public void setCreatedate(Date createdate) {
this.createdate = createdate;
}
}
class Dept{
private String dname;
private String loc;
private Company company;
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
}
如果要通过Emp进行操作,则应该使用“.”作为级联关系的处理:
dept.dname:财务部 | Emp类实例化对象.getDept().setName(“财务部”) |
dept.company.name:MLDN | Emp实例化类对象.getDept().getCompany().setName(“MLDN”) |
考虑到代码的简洁性,应该考虑可以通过级联的配置自动实现类中属性的实例化。
现在的属性存在有多级的关系,必须与单级的配置区分开。
class BeanUtils {
private BeanUtils() {
}
/**
* 实现指定对象的属性设置
* @param obj 要进行反射操作的实例化对象
* @param value 包含有指定内容的字符串,格式“属性:内容|属性:内容”
*/
public static void setValue(Object obj, String value) {
String results [] = value.split("\\|");//按照“|”进行分组拆分
for(int x=0; x< results.length;x++) {//循环设置属性内容
//attval[0]保存的是属性名称、attval[1]保存的是属性内容
String attval[] = results[x].split(":");//获取“属性名称”与内容
try {
if(attval[0].contains(".")) {//多级配置
String temp[] = attval[0].split("\\.");
Object currentObject = obj;
// System.out.println(Arrays.toString(temp));
//最后一位肯定是指定类中的属性名称,所以不在本次实例化处理的范围内
for(int y = 0; y < temp.length - 1;y++) {
System.out.println(temp[y]);
//调用相应的getter方法,如果getter方法返回了null表示该对象未实例化
Method getMethod = currentObject.getClass().getDeclaredMethod("get"+StringUtils.initcap(temp[y]));
Object tempObject = getMethod.invoke(currentObject);
if(tempObject == null) {//该对象现在并没有被实例化
Field field = currentObject.getClass().getDeclaredField(temp[y]);//获取属性类型
Method method = currentObject.getClass().getDeclaredMethod("set" + StringUtils.initcap(temp[y]), field.getType());
Object newObject = field.getType().getDeclaredConstructor().newInstance();
method.invoke(currentObject, newObject);
currentObject = newObject;
}else {
currentObject = tempObject;
}
// System.out.println(temp[y] + "--" + currentObject);
}
}else {
Field field = obj.getClass().getDeclaredField(attval[0]);//获取成员
Method setMethod = obj.getClass().getDeclaredMethod("set"+StringUtils.initcap(attval[0]), field.getType());
Object convertValue = BeanUtils.convertAttributeValue(field.getType().getName(), attval[1]);
setMethod.invoke(obj, convertValue);//调用setter 方法设置内容
}
}catch(Exception e) {
}
}
}
/**
* 实现属性类型转换处理
*
* @param type 属性类型,通过Field获取
* @param value 属性 的内容,传入的都是字符串,需要将其转变为指定类型
* @return 转换后的数据
*/
private static Object convertAttributeValue(String type, String value) {
// System.out.println("type =" + type + "、value=" + value);
if ("long".equals(type) || "java.lang.Long".equals(type)) {
return Long.parseLong(value);
} else if ("int".equals(type) || "java.lang.int".equals(type)) {
return Integer.parseInt(value);
} else if ("double".equals(type) || "java.lang.double".equals(type)) {
return Double.parseDouble(value);
} else if ("java.util.Date".equals(type)) {
SimpleDateFormat sdf = null;
if (value.matches("\\d{4}-\\d{2}-\\d{2}")) {
sdf = new SimpleDateFormat("yyyy-MM-dd");
} else if (value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) {
sdf = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss");
} else {
return new Date();// 当前日期
}
try {
return sdf.parse(value);
} catch (ParseException e) {
return new Date();
}
} else {
return value;
}
}
}
级联属性设置
//最后一位肯定是指定类中的属性名称,所以不在本次实例化处理的范围内
for(int y = 0; y < temp.length - 1;y++) {
System.out.println(temp[y]);
//调用相应的getter方法,如果getter方法返回了null表示该对象未实例化
Method getMethod = currentObject.getClass().getDeclaredMethod("get"+StringUtils.initcap(temp[y]));
Object tempObject = getMethod.invoke(currentObject);
if(tempObject == null) {//该对象现在并没有被实例化
Field field = currentObject.getClass().getDeclaredField(temp[y]);//获取属性类型
Method method = currentObject.getClass().getDeclaredMethod("set" + StringUtils.initcap(temp[y]), field.getType());
Object newObject = field.getType().getDeclaredConstructor().newInstance();
method.invoke(currentObject, newObject);
currentObject = newObject;
}else {
currentObject = tempObject;
}
// System.out.println(temp[y] + "--" + currentObject);
}
当此时循环处理完成之后,currentObject表示单级ius可以进行setter方法调用的对象了,并且该对象理论上一定不为空。随后就可以按照之前的方式利用对象进行setter调用。
【范例】实现对象级联属性设置
//进行属性内容设置
Field field = currentObject.getClass().getDeclaredField(temp[temp.length-1]);//获取成员
Method setMethod = currentObject.getClass().getDeclaredMethod("set" + StringUtils.initcap(temp[temp.length-1]), field.getType());
Object convertValue = BeanUtils.convertAttributeValue(field.getType().getName(), attval[1]);
setMethod.invoke(currentObject, convertValue);//调用setter 方法设置内容
}else {
Field field = obj.getClass().getDeclaredField(attval[0]);//获取成员
Method setMethod = obj.getClass().getDeclaredMethod("set"+StringUtils.initcap(attval[0]), field.getType());
Object convertValue = BeanUtils.convertAttributeValue(field.getType().getName(), attval[1]);
setMethod.invoke(obj, convertValue);//调用setter 方法设置内容
以后开发之中简单Java类的复制处理将不再重复嗲用setter操作完成,而这种处理形式是在正规开发之中普遍采用形式。
完整代码:
package demo;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
public class JavaAPIDemo {
public static void main(String[] args) throws Exception {
String value = "empno:940525|ename:Smithi|job:Clerk|salary:9999.88|hiredate:1994-05-25"
+ "|dept.dname:财务部|dept.company.name:MLDN";
Emp emp = ClassInstanceFactory.create(Emp.class, value);
System.out.println("工号:" + emp.getEmpno() + "姓名:" + emp.getEname() + "、职位:" + emp.getJob() + "、薪水:"
+ emp.getSalary() + "、雇佣日期:" + emp.getHiredate());
System.out.println(emp.getDept().getDname());
System.out.println(emp.getDept().getCompany().getName());
}
}
class ClassInstanceFactory {
private ClassInstanceFactory() {
}
/**
* 实例化对象的创建方法,该对象可以根据传入的字符串结构“属性:内容|属性:内容”
*
* @param <T>
* @param clazz 要进行反射实例化的Class类对象,有Class就可以反射实例化对象
* @param value 要设置给对象的属性内容
* @return 一个已经配置好属性内容的Java类对象
*/
public static <T> T create(Class<?> clazz, String value) {
// 如果要想采用反射机型简单Java类对象属性设置的时候,类中必须要有无参构造
try {
Object obj = clazz.getDeclaredConstructor().newInstance();
BeanUtils.setValue(obj, value);// 通过反射设置属性
return (T) obj;// 返回对象
} catch (Exception e) {
e.printStackTrace();
return null;
}
}
}
class StringUtils {
public static String initcap(String str) {
if (str == null || "".equals(str)) {
return str;
}
if (str.length() == 1) {
return str.toUpperCase();
} else {
return str.substring(0, 1).toUpperCase() + str.substring(1);
}
}
}
class BeanUtils {
private BeanUtils() {
}
/**
* 实现指定对象的属性设置
* @param obj 要进行反射操作的实例化对象
* @param value 包含有指定内容的字符串,格式“属性:内容|属性:内容”
*/
public static void setValue(Object obj, String value) {
String results [] = value.split("\\|");//按照“|”进行分组拆分
for(int x=0; x< results.length;x++) {//循环设置属性内容
//attval[0]保存的是属性名称、attval[1]保存的是属性内容
String attval[] = results[x].split(":");//获取“属性名称”与内容
try {
if(attval[0].contains(".")) {//多级配置
String temp[] = attval[0].split("\\.");
Object currentObject = obj;
// System.out.println(Arrays.toString(temp));
//最后一位肯定是指定类中的属性名称,所以不在本次实例化处理的范围内
for(int y = 0; y < temp.length - 1;y++) {
System.out.println(temp[y]);
//调用相应的getter方法,如果getter方法返回了null表示该对象未实例化
Method getMethod = currentObject.getClass().getDeclaredMethod("get"+StringUtils.initcap(temp[y]));
Object tempObject = getMethod.invoke(currentObject);
if(tempObject == null) {//该对象现在并没有被实例化
Field field = currentObject.getClass().getDeclaredField(temp[y]);//获取属性类型
Method method = currentObject.getClass().getDeclaredMethod("set" + StringUtils.initcap(temp[y]), field.getType());
Object newObject = field.getType().getDeclaredConstructor().newInstance();
method.invoke(currentObject, newObject);
currentObject = newObject;
}else {
currentObject = tempObject;
}
}
//进行属性内容设置
Field field = currentObject.getClass().getDeclaredField(temp[temp.length-1]);//获取成员
Method setMethod = currentObject.getClass().getDeclaredMethod("set" + StringUtils.initcap(temp[temp.length-1]), field.getType());
Object convertValue = BeanUtils.convertAttributeValue(field.getType().getName(), attval[1]);
setMethod.invoke(currentObject, convertValue);//调用setter 方法设置内容
}else {
Field field = obj.getClass().getDeclaredField(attval[0]);//获取成员
Method setMethod = obj.getClass().getDeclaredMethod("set"+StringUtils.initcap(attval[0]), field.getType());
Object convertValue = BeanUtils.convertAttributeValue(field.getType().getName(), attval[1]);
setMethod.invoke(obj, convertValue);//调用setter 方法设置内容
}
}catch(Exception e) {
}
}
}
/**
* 实现属性类型转换处理
*
* @param type 属性类型,通过Field获取
* @param value 属性 的内容,传入的都是字符串,需要将其转变为指定类型
* @return 转换后的数据
*/
private static Object convertAttributeValue(String type, String value) {
// System.out.println("type =" + type + "、value=" + value);
if ("long".equals(type) || "java.lang.Long".equals(type)) {
return Long.parseLong(value);
} else if ("int".equals(type) || "java.lang.int".equals(type)) {
return Integer.parseInt(value);
} else if ("double".equals(type) || "java.lang.double".equals(type)) {
return Double.parseDouble(value);
} else if ("java.util.Date".equals(type)) {
SimpleDateFormat sdf = null;
if (value.matches("\\d{4}-\\d{2}-\\d{2}")) {
sdf = new SimpleDateFormat("yyyy-MM-dd");
} else if (value.matches("\\d{4}-\\d{2}-\\d{2} \\d{2}:\\d{2}:\\d{2}")) {
sdf = new SimpleDateFormat("yyyy-MM-DD HH:mm:ss");
} else {
return new Date();// 当前日期
}
try {
return sdf.parse(value);
} catch (ParseException e) {
return new Date();
}
} else {
return value;
}
}
}
class Company {
private String name;
private Date createdate;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
public Date getCreatedate() {
return createdate;
}
public void setCreatedate(Date createdate) {
this.createdate = createdate;
}
}
class Dept {
private String dname;
private String loc;
private Company company;
public String getDname() {
return dname;
}
public void setDname(String dname) {
this.dname = dname;
}
public String getLoc() {
return loc;
}
public void setLoc(String loc) {
this.loc = loc;
}
public Company getCompany() {
return company;
}
public void setCompany(Company company) {
this.company = company;
}
}
class Emp {
private long empno;
private String ename;
private String job;
private double salary;
private Date hiredate;
private Dept dept;
public String getEname() {
return ename;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
public void setEname(String ename) {
this.ename = ename;
}
public String getJob() {
return job;
}
public void setJob(String job) {
this.job = job;
}
public Long getEmpno() {
return empno;
}
public void setEmpno(long empno) {
this.empno = empno;
}
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public Date getHiredate() {
return hiredate;
}
public void setHiredate(Date hiredate) {
this.hiredate = hiredate;
}
}
参考:https://edu.aliyun.com/lesson_1012_9059#_9059