级联对象实例化
上一节设置多种数据类型
如果现在给定的类对象之中存在有其他的引用的级联关系的情况下,称为多级设置。
例如一个雇员属于一个部门,一个部门属于一个公司,所以这个时候对于简单Java类的基本关系定义如下:(setter、getter略)
class Company{
private String name;
private Date createDate;
}
class Dept{
private String name;
private String loc;
private Company company;
}
class Emp {
private String eName;
private String job;
private double salary;
private long empno;
private Dept dept;
}
如果要通过Emp进行操作,则应该使用“.”作为级联关系处理:
dept.dname:财务部 | Emp类实例化对象.getDept().setDname("财务部") |
dept.company.name:腾讯 | Emp类实例化对象.getDept().getCompany.setName("腾讯") |
考虑到代码的简介性,应该考虑可以通过级联的配置自动实现类中属性的实例化。现在的属性存在有多级的关系,那么对于多级的关系就必须与单级的配置区分开。
package reflect;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
import java.text.ParseException;
import java.text.SimpleDateFormat;
import java.util.Date;
public class Demo{
public static void main(String[] args) throws Exception{
String value = "eName:Smith|job:Clerk|salary:8912.12|empno:1"+"|dept.name:财务部|dept.company.name:腾讯";
Emp emp = ClassInstanceFactory.create(Emp.class,value);
System.out.println("雇员编号:"+emp.getEmpno()+"、姓名:"+emp.getEName()+"、职位:"+ emp.getJob()+"、薪资:"+emp.getSalary()
+"、部门:"+emp.getDept().getName()+"、公司:"+emp.getDept().getCompany().getName());
}
}
class ClassInstanceFactory{
private ClassInstanceFactory(){}
/**
* 实例化对象的创建方法,该对象可以根据传入的字符串结构“属性:内容|属性:内容”传入
* @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); //调用BeanUtil实现属性的更改
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{ //进行Bean处理的类
private BeanUtils(){}
/**
* 实现指定对象的属性设置
* @param obj 要进行反射操作的实例化对象
* @param value 包含有指定内容的字符窜,格式为"属性:内容|属性:内容"
*/
public static void setValue(Object obj,String value){
String[] result = value.split("\\|"); //按照“|”进行每一组属性的拆分
for(int x = 0;x < result.length;x++){ //循环设置属性内容
//attval[0]保存的是属性名称,attval[1]保存的是内容
String[] attval = result[x].split(":"); //获取“属性名称”与“内容”\
try{
if(attval[0].contains(".")){ //多级配置
String[] temp = attval[0].split("\\.");
Object currentObject = obj;
//最后一位肯定是类中属性名称,所以不再本次实例化处理的范畴之内
for(int i = 0; i <temp.length -1;i++ ){ //实例化对象
//调用相应的getter方法,如果getter方法返回了null表示该对象未实例化
Method getMethod = currentObject.getClass().getMethod("get"+StringUtils.initcap(temp[i]));
Object tempObject = getMethod.invoke(currentObject); //调用geter方法
if(tempObject == null){ //该对象并没有实例化
Field filed = currentObject.getClass().getDeclaredField(temp[i]); //获取属性类型
//获取set对象的方法
Method method = currentObject.getClass().getDeclaredMethod("set"
+StringUtils.initcap(temp[i]),filed.getType());
//调用setter方法并调用,填入实例化对象
Object NewObject = filed.getType().getDeclaredConstructor().newInstance();
method.invoke(currentObject,NewObject);
currentObject = NewObject;
}else{
currentObject = tempObject;
}
}
//进行属性内容的设置
Field filed = currentObject.getClass().getDeclaredField(temp[temp.length-1]); //获取成员
//获取set方法
Method setMethod = currentObject.getClass().getMethod("set"+StringUtils.initcap(temp[temp.length-1]),filed.getType());
//进行数据的转型
Object val = BeanUtils.convertAttributeValue(filed.getType().getName(),attval[1]);
setMethod.invoke(currentObject,val); //调用setter方法进行赋值
}else{ //单级配置
Field filed = obj.getClass().getDeclaredField(attval[0]); //获取成员
//根据取名规范set+首字母大写属性获取方法
Method setMethod = obj.getClass().getMethod("set"+StringUtils.initcap(attval[0]),filed.getType());
//进行数据的转型
Object val = BeanUtils.convertAttributeValue(filed.getType().getName(),attval[1]);
setMethod.invoke(obj,val); //调用setter方法进行赋值
}
}catch (Exception e){
e.printStackTrace();
}
}
}
/**
* 实现属性 类型转换处理
* @param type 属性类型,通过Filed获取的
* @param value 属性的内容,传入的都是字符串,需要将其变为指定类型
* @return 转换后的数据
*/
private static Object convertAttributeValue(String type,String value){
if("long".equals(type) || "java.lang.Long".equals(type)){
return Long.parseLong(value);
}else if("int".equals(type) || "java.lang.Integer".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 simpleDateFormat = null;
if(value.matches("\\d{4}-\\d{2}-\\d{2}")){ //日期类型
simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd");
}else if(value.matches("\\d{4}-\\d{2}-\\d{2}:\\d{2}:\\d{2}:\\d{2}")){
return simpleDateFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
}else{
return new Date(); //当前日期
}
try {
return simpleDateFormat.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 name;
private String loc;
private Company company;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
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 String eName;
private String job;
private double salary;
private long empno;
private Dept dept;
public double getSalary() {
return salary;
}
public void setSalary(double salary) {
this.salary = salary;
}
public long getEmpno() {
return empno;
}
public void setEmpno(long empno) {
this.empno = empno;
}
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 String geteName() {
return eName;
}
public void seteName(String eName) {
this.eName = eName;
}
public Dept getDept() {
return dept;
}
public void setDept(Dept dept) {
this.dept = dept;
}
}
雇员编号:1、姓名:Smith、职位:Clerk、薪资:8912.12、部门:财务部、公司:腾讯
在以后的开发之中简单Java类的复制处理将不再重复调用setter操作完成,而这种处理是在正规开发中普遍采用的方式。