记录一次对象属性拷贝中反射的应用
1.常用反射机制的方法
常用的反射机制,比如BeanUtil.copyProperties()
,是一种常见的用于对象属性拷贝的工具方法。它通常用于将一个对象的属性值复制到另一个对象中。
简单的使用示例:
1. 创建源对象和目标对象:
```
SourceObject source = new SourceObject();
TargetObject target = new TargetObject();
```
2. 使用`BeanUtil.copyProperties()`进行属性拷贝:
```
BeanUtils.copyProperties(source, target);
```
该方法会自动将源对象的属性值拷贝到目标对象中,前提是源对象和目标对象拥有相同的属性名和类型。如果属性名不一致,可以考虑使用`@PropertyName`注解进行映射。
```
BeanUtils.copyProperties(source, target, "propertyName1", "propertyName2");
```
在这种情况下,只有在显式指定的属性名匹配时,属性值才会被拷贝。
2.尝试仿写
我们试着简单写一个类似的方法,即根据属性名和类型将源对象的属性值复制到目标对象中。
copyMatchedFields
//反射将一个实体类的字段保存到另一个
public static <T1, T2> void copyMatchedFields(T1 source, T2 target) throws Exception {
Field[] sourceFields = source.getClass().getDeclaredFields();
Field[] targetFields = target.getClass().getDeclaredFields();
for (Field sourceField : sourceFields) {
for (Field targetField : targetFields) {
if (sourceField.getName().equals(targetField.getName())
&& sourceField.getType().equals(targetField.getType())) {
sourceField.setAccessible(true);
targetField.setAccessible(true);
Object value = sourceField.get(source);
targetField.set(target, value);
}
}
}
}
//使用
copyMatchedFields(source, target);
大体解释一下
使用泛型
<T1, T2>
,表示该方法可以处理不同类型的源对象和目标对象。通过
source.getClass().getDeclaredFields()
获取源对象的字段数组,通过target.getClass().getDeclaredFields()
获取目标对象的字段数组。使用两个循环遍历源对象和目标对象的字段。
判断源对象和目标对象的字段名以及字段类型是否匹配。
sourceField.getName().equals(targetField.getName())
判断字段名是否相同。
sourceField.getType().equals(targetField.getType())
判断字段类型是否相同。设置可访问性为
true
,以便在私有字段上进行操作:sourceField.setAccessible(true)
、targetField.setAccessible(true)
。使用
sourceField.get(source)
获取源对象字段的值。使用
targetField.set(target, value)
将源对象字段的值设置到目标对象字段上。需要注意的是,该方法只会复制属性名和类型匹配的字段。如果源对象和目标对象具有相同名称但类型不匹配的字段,这个方法将不会复制它们的值。
3.注意事项
这里要注意一下,如果源对象和目标对象存在不同的字段,使用我们的方法或BeanUtils.copyProperties()
方法时会尽可能拷贝相同字段名和类型的属性值。对于不同字段名或类型的属性,将不会进行拷贝。
如果源对象和目标对象中存在不同的字段,在调用BeanUtils.copyProperties()
方法时会忽略这些不同的字段,不会导致执行失败。仅会拷贝源对象和目标对象中具有相同字段名和类型的属性值。
这是因为BeanUtils.copyProperties()
方法将根据字段名和类型进行匹配和拷贝,如果字段名或类型不匹配,则会被忽略。
这里我们做一个验证
public class SourceObject {
private String field1;
private int field2;
//...
// getter and setter
}
public class TargetObject {
private String field1;
private boolean field3;
//...
// getter and setter
}
SourceObject source = new SourceObject();
source.setField1("value1");
source.setField2(10);
TargetObject target = new TargetObject();
BeanUtils.copyProperties(source, target);
System.out.println(target.getField1()); // 输出:value1
System.out.println(target.isField3()); // 输出:false(boolean的默认值)
在上述验证示例中,SourceObject
和TargetObject
具有不同的字段 field2
和 field3
。通过BeanUtils.copyProperties()
方法,只有字段名为 field1
的属性值被成功拷贝到目标对象 TargetObject
中。其他字段名不匹配的属性将会被忽略。
因此,在使用BeanUtils.copyProperties()
方法时,请确保源对象和目标对象中需要拷贝的字段具有相同的字段名和类型,以确保属性的拷贝可以顺利进行。