有两个java对象:想将类Source的属性值复制给类Target,根据相同属性名赋值。
通过反射复制相似对象的属性。两个对象类似,但有部分属性名不同,但想要将相同属性名的值传递过去。
场景:
有两个java对象:想将Source的属性名相同的属性复制给Target。
@Data
class Source{
String name;
Source ceShi;
String aDouble;
}
@Data
class Target{
String name;
Source ceShi;
Double aD;
}
最简单粗暴的办法是直接,写一个方法,挨个把属性set赋值进去。
问题是下次再遇到类似场景,还要再重写一个方法,不具有普适性,很麻烦。
有没有什么一劳永逸的方法?
实现思路:
目标是:将source对象复制给target对象,虽然两个对象的父类都是Object,但当调用方法时传入的两个对象未知类型。
/**
* 将source的属性赋值给target相应属性<br/>
* 注意:<br/>
* 1.source和target的属性名相同时,属性类型也必须相同<br/>
* 2.source和target的属性类型必须全部为基础属性的包装类或其他类,不能使用类似<T>这种泛型。
* 如:只能写为Boolean,不能为boolean<br/>
* 3.source和target所有属性必须有set方法,其属性类型和其get/set方法参数类型必须相同。<br/>
* 4.浅复制,若source里的某属性为一对象,相当于直接让target的属性等于source里的属性对象<br/>
*
* @param source
* @param target
*/
public static void injectSetField(Object source,Object target) throws Exception {
//得到class
Class<?> sourceClass = source.getClass();
Class<?> targetClass = target.getClass();
//得到obj所有属性
Field[] objFields = sourceClass.getDeclaredFields();
Field[] tarFields = targetClass.getDeclaredFields();
//子方法:数组转map,key为属性名,val为Field对象
Map<String, Field> tarMap = fieldsToMap(tarFields);
//遍历objFields
for (int i = 0; i < objFields.length; i++) {
//属性名
//得到属性
Field field = objFields[i];
//打开私有访问
field.setAccessible(true);
//获取属性
String name = field.getName();
if (tarMap.containsKey(name)){
//存在该属性,可以进行复制
//获取属性值
Object value = field.get(source);
//子方法:对target对象的属性name赋值value
injectSetField_1(target, name, value);
}
}
}
上面方法逻辑是:通过反射获取source和target两个对象的属性数组Field[],比较两个数组,有相同属性的,就调用给对象反射赋值的子方法。
就是下一个方法。
/**
* 给对象model 的属性attrName 赋值为 attrVal。
* 浅复制,属性为对象不为基础类型,则直接赋给对象。
* 注意:model不能使用<T>这种泛型,且其属性的类型必须全部为包装类,即不能写boolean,必须为Boolean,
* 其model的get/set方法里参数也必须为Boolean这种
* @param model
* @param attrName
* @param attrVal
* @return
* @throws Exception
*/
public static void injectSetField_1(Object model, String attrName,Object attrVal) throws Exception {
Field[] field = model.getClass().getDeclaredFields(); // 获取实体类的所有属性,返回Field数组
//用于转换attrVal
Object val;
for (int j = 0; j < field.length; j++) { // 遍历所有属性
String name = field[j].getName(); // 获取属性的名字
Class<?> type = field[j].getType();
//找到了该属性,进行赋值操作
if (name.equals(attrName)) {
//attrVal转换为其类型,若类型不一致,为null
val = convertByType(attrVal, type);
name = name.substring(0, 1).toUpperCase() + name.substring(1); // 将属性的首字符大写,方便构造get,set方法
Method m = null;
if (attrVal != null){
if (val != null)
{
m = model.getClass().getMethod("set" + name, val.getClass());
m.invoke(model, val);
}else {
m = model.getClass().getMethod("set" + name, attrVal.getClass());
m.invoke(model, attrVal);
}
}
}
}
}
上面这个方法是传入3个参数,对象,属性名,属性值。给对象的属性赋值。
逻辑是通过反射调用其对象的set方法,来进行属性的赋值。
下面是两个工具方法,都是上面方法中需要使用的:
1.将field[]数组转map
2.Object对象转成指定的类型对象
/**
* field[]数组转map
* @param fields 属性数组
* @return map
*/
public static Map<String, Field> fieldsToMap(Field[] fields){
HashMap<String, Field> hashMap = new HashMap<>();
for (Field field : fields) {
//打开私有访问
field.setAccessible(true);
String name = field.getName();
hashMap.put(name, field);
}
return hashMap;
}
/**
* Object转成指定的类型type
* @param obj
* @param type
* @param <T>
* @return
*
*/
public static<T> T convertByType(Object obj, Class<T> type) {
if (obj != null && ItsStringUtil.isNotEmpty(obj.toString())) {
if (type.equals(Integer.class)||type.equals(int.class)) {
return (T)new Integer(obj.toString());
} else if (type.equals(Long.class)||type.equals(long.class)) {
return (T)new Long(obj.toString());
} else if (type.equals(Boolean.class)||type.equals(boolean.class)) {
return (T) new Boolean(obj.toString());
} else if (type.equals(Short.class)||type.equals(short.class)) {
return (T) new Short(obj.toString());
} else if (type.equals(Float.class)||type.equals(float.class)) {
return (T) new Float(obj.toString());
} else if (type.equals(Double.class)||type.equals(double.class)) {
return (T) new Double(obj.toString());
} else if (type.equals(Byte.class)||type.equals(byte.class)) {
return (T) new Byte(obj.toString());
} else if (type.equals(Character.class)||type.equals(char.class)) {
return (T)new Character(obj.toString().charAt(0));
} else if (type.equals(String.class)) {
return (T) obj;
} else if (type.equals(BigDecimal.class)) {
return (T) new BigDecimal(obj.toString());
} else if (type.equals(LocalDateTime.class)) {
return (T) LocalDateTime.parse(obj.toString());
} else if (type.equals(Date.class)) {
return (T)((Date)obj);
}else{
return null;
}
} else {
if (type.equals(int.class)) {
return (T)new Integer(0);
} else if (type.equals(long.class)) {
return (T)new Long(0L);
} else if (type.equals(boolean.class)) {
return (T)new Boolean(false);
} else if (type.equals(short.class)) {
return (T)new Short("0");
} else if (type.equals(float.class)) {
return (T) new Float(0.0);
} else if (type.equals(double.class)) {
return (T) new Double(0.0);
} else if (type.equals(byte.class)) {
return (T) new Byte("0");
} else if (type.equals(char.class)) {
return (T) new Character('\u0000');
}else {
return null;
}
}
}
main测试
public static void main(String[] args) {
Source source = new Source();
source.setADouble("123456");
source.setName("name1");
source.setSource(new Source());
Target two =new Target();
System.out.println(source);
System.out.println(two);
System.out.println("-----------");
try {
injectSetField(source,two);
} catch (Exception e) {
e.printStackTrace();
}
System.out.println(source);
System.out.println(two);
}
}
测试结果:


版权声明:本文为qq_43220949原创文章,遵循CC 4.0 BY-SA版权协议,转载请附上原文出处链接和本声明。