Java自定义copyProperties,实现不同对象的相同属性(包含子对象)赋值

发布时间:2022-09-02 04:30

Java自定义Copy属性

工具类中自带的BeanUtil.copyProperties只能赋值基本类型的属性。对于复杂类型:如List、Map仍然需要手动赋值。于是乎,自己定义了一个copyProperties工具方法,实现对复杂类型的的赋值。用于实体类与VO对象之间的复制。

实现共定义了四个方法,一个常用类(generalType)集合。除常用类、集合、列表以及数组之外,认为其他类型是自定义类型。

  1. 方法:copyProperties,公共,用于两个对象之间相同属性赋值,对象类型可同可不同;
  2. 方法:copyCollection,私有,不公开,用于集合之间赋值;
  3. 方法: copyList,公共,用于A泛型列表(List)转换为B泛型列表,默认为ArrayList类型。如果源对象字段属性和目标对象字段类型为不同的List,赋值类型以目标属性为主,如果目标属性为List类型,则字段属性类型以源对象字段属性类型为主
  4. 方法:copySet:公共,用于A泛型Set集合转换为B泛型集合,默认为HashSet类型。 如果源对象字段属性和目标对象字段类型为不同的Set,赋值类型以目标属性为主,如果目标属性为Set类型,则字段属性类型以源对象字段属性类型为主

代码:

  1. BeanUtil
import java.lang.reflect.*;
import java.util.*;

public final class BeanUtil {
    /**
     * 定义所有的基本类型及包装类型,或者是String、Date
     */
    private static final List<String> generalType = new ArrayList<String>() {{
        add(Integer.class.getName());
        add(Double.class.getName());
        add(Float.class.getName());
        add(Long.class.getName());
        add(Short.class.getName());
        add(Byte.class.getName());
        add(Boolean.class.getName());
        add(Character.class.getName());
        add(String.class.getName());
        add(Date.class.getName());
        add("int");
        add("double");
        add("float");
        add("long");
        add("short");
        add("byte");
        add("boolean");
        add("char");
    }};

    /**
     * 用于两个对象属性名相同之间的复制
     * 

* 支持字段类型: * 1. 所有基本类型 ; * 2. String; * 3. Date; * 4. List(允许源对象、目标对象类型不一致,以目标对象为主。抽象类默认为ArrayList); * 5. Map 其中S,T为基本类型、String、Date、自定义类型, * 6. Set(允许源对象、目标对象类型不一致,以目标对象为主。抽象类默认为HashSet); * 7. 自定义对象,包含自己本身,可以实现无限层级复制字段值(最重要的功能) * 8. 其他未知 * * @param source 原资源对象 * @param target 目标资源对象 * @param 目标类型 * @param 原资源类型 * @return */ public static final <T, S> T copyProperties(S source, T target) { try { Class<?> sClass = source.getClass(); Class<?> tClass = target.getClass(); // 如果source为基本类型,直接复制 if (generalType.contains(sClass.getName())) { target = (T) source; return target; } // 获取所有字段 Field[] fields = sClass.getDeclaredFields(); for (int i = 0; i < fields.length; i++) { Field sField = fields[i]; // 获取字段Class Class<?> sFieldClass = sField.getType(); // 获取字段名 String name = sField.getName(); // 获取字段值 String firstLetter = name.substring(0, 1).toUpperCase(); String getter = "get" + firstLetter + name.substring(1); // 对象类型使用get方法 Method getMethod = sClass.getDeclaredMethod(getter, new Class[]{}); Object value = getMethod.invoke(source, new Object[]{}); if (value == null) { // 值为空,跳过 continue; } // 获取目标类字段 Field tField; try{ // 尝试获取属性字段,获取不到不复制 tField = tClass.getDeclaredField(name); }catch (Exception e){ continue; } Class<?> tFieldClass = tField.getType(); String setter = "set" + firstLetter + name.substring(1); Method setMethod = tClass.getDeclaredMethod(setter, tFieldClass); if (generalType.contains(sFieldClass.getName())) { // 基本类型 + String + Date,直接复制值 /** * 判断源字段属性的类型和目标字段属性类型一致,进行赋值,否则跳过 */ if (tFieldClass.getName().equals(sFieldClass.getName())) { setMethod.invoke(target, value); } } else if (tFieldClass.isArray()) { // 数组类型 // 获取数组的Class Class<?> componentType = tFieldClass.getComponentType(); if (generalType.contains(componentType.getName())) { // 如果为通用类型数组,进行复制 setMethod.invoke(target, value); } else { // 复杂类型使用该方法复制 Object[] arr = (Object[]) value; Object targetArr = Array.newInstance(componentType, arr.length); for (int j = 0; j < arr.length; j++) { Object itemSource = arr[j]; // 定义目标对象 Object itemTarget = componentType.newInstance(); // 复制对象 copyProperties(itemSource, itemTarget); // 添加到对应数组 Array.set(targetArr, j, itemTarget); } // 复制属性 setMethod.invoke(target, targetArr); } } else if (List.class.isAssignableFrom(tFieldClass)) { // 列表类型 // 强转列表值 List listValue = (List) value; // 获取列表中的泛型 Type genericType = tField.getGenericType(); // 获取类型Class if (genericType instanceof ParameterizedType) { ParameterizedType typeCls = (ParameterizedType) genericType; // 列表中的泛型类型 Class subGenericClass = (Class<?>) typeCls.getActualTypeArguments()[0]; // 最终属性值,默认转成了ArrayList List targetList = copyList(listValue, subGenericClass); // 复制属性值 // 如果为抽象类,或者目标类型与源类型相同,直接复制 if (tFieldClass == List.class || tFieldClass == targetList.getClass()) { // 默认为ArrayList setMethod.invoke(target, targetList); } else { // 其他List List otherList = (List) tFieldClass.newInstance(); // 转换目标类型列表 targetList.stream().forEach(item -> otherList.add(item)); // 复制 setMethod.invoke(target, otherList); } } } else if (Set.class.isAssignableFrom(tFieldClass)) { // 列表类型 // 强转列表值 Set listValue = (Set) value; // 获取列表中的泛型 Type genericType = tField.getGenericType(); // 获取类型Class if (genericType instanceof ParameterizedType) { ParameterizedType typeCls = (ParameterizedType) genericType; // 列表中的泛型类型 Class subGenericClass = (Class<?>) typeCls.getActualTypeArguments()[0]; // 最终属性值,默认转成了ArrayList Set targetSet = copySet(listValue, subGenericClass); // 复制属性值 // 如果为抽象类,或者目标类型与源类型相同,直接复制 if (tFieldClass == Set.class || tFieldClass == targetSet.getClass()) { // 默认为ArrayList setMethod.invoke(target, targetSet); } else { // 其他List Set otherSet = (Set) tFieldClass.newInstance(); // 转换目标类型列表 targetSet.stream().forEach(item -> otherSet.add(item)); // 复制 setMethod.invoke(target, otherSet); } } } else if (Map.class.isAssignableFrom(tFieldClass)) { // 集合类型 // 强转集合 Map mapValue = (Map) value; // key值集合 List keys = new ArrayList(mapValue.keySet()); // value值集合 List values = new ArrayList(mapValue.values()); // 获取列表中的泛型 Type genericType = tField.getGenericType(); // 获取类型Class if (genericType instanceof ParameterizedType) { ParameterizedType typeCls = (ParameterizedType) genericType; // 获取key的类型 Class keyClass = (Class) typeCls.getActualTypeArguments()[0]; // 获取value的类型 Class valueClass = (Class) typeCls.getActualTypeArguments()[1]; // 转换keys集合 List targetKeysList = copyList(keys, keyClass); // 转换values集合 List targetValuesList = copyList(values, valueClass); // 实例化map对象 Map targetValue; try { // 属性可能使用具体类 targetValue = (Map) tFieldClass.newInstance(); } catch (Exception e) { // 如果使用抽象类,则使用value值的类型 targetValue = (Map) value.getClass().newInstance(); } // 转换目标Map集合 for (int j = 0; j < targetKeysList.size(); j++) { Object targetMapKey = targetKeysList.get(j); Object targetMapValue = targetValuesList.get(j); targetValue.put(targetMapKey, targetMapValue); } // 复制属性 setMethod.invoke(target, targetValue); } } else { // 自定义对象类型 // 定义目标对象 Object targetValue = tFieldClass.newInstance(); // 复制子属性值 copyProperties(value, targetValue); // 复制属性值 setMethod.invoke(target, targetValue); } } return target; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 复制集合 * @param source * @param target * @param targetClass * @param * @param */ private static final <T, S> void copyCollection(Collection<S> source, Collection<T> target, Class<T> targetClass) { source.stream().forEach(item -> { try { T t; // 如果是基本类型 if (generalType.contains(targetClass.getName())) { target.add((T) item); } else { t = targetClass.newInstance(); copyProperties(item, t); target.add(t); } } catch (Exception e) { e.printStackTrace(); } }); } /** * 实体类与VO对象列表的copy * 转换后以源列表为主,默认为ArrayList * * @param source 数据源列表 * @param targetClass 目标列表中对象类Class * @param 目标列表类型 * @param 数据源列表类型 * @return */ public static final <T, S> List<T> copyList(List<S> source, Class<T> targetClass) { List<T> target; try { if (source.getClass() == List.class || source.getClass() == ArrayList.class) { target = new ArrayList<>(); } else { target = source.getClass().newInstance(); } List<T> finalTarget = target; copyCollection(source, target, targetClass); return finalTarget; } catch (Exception e) { e.printStackTrace(); } return null; } /** * 实体类与VO对象Set列表的copy * 转换后的集合类型以源类型为主,默认为HashSet * * @param source 数据源列表 * @param targetClass 目标列表中对象类Class * @param 目标列表类型 * @param 数据源列表类型 * @return */ public static final <T, S> Set<T> copySet(Set<S> source, Class<T> targetClass) { Set<T> target; try { if (source.getClass() == Set.class || source.getClass() == HashSet.class) { target = new HashSet<>(); } else { target = source.getClass().newInstance(); } Set<T> finalTarget = target; copyCollection(source, target, targetClass); return finalTarget; } catch (Exception e) { e.printStackTrace(); } return null; } }

  1. 测试源类型:Copy
public class Copy {
    private Integer a;
    private double b;
    private String c;
    private Date d;
    private Test test;
    private Test[] tests;
    private int[] e;
    private LinkedList<Test> f;
    private Map<Integer,String> map;
    private Map<Test,Test> mapObj;
    private Set<Test> setList;
    private Copy copy;
	// ... get、set、toString 略
}
  1. 测试目标类型:CopyVO
public class CopyVO {
    private Integer a;
    private double b;
    private String c;
    private Date d;
    private TestVO test;
    private TestVO[] tests;
    private int[] e;
    private ArrayList<TestVO> f;
    private Map<Integer,String> map;
    private Map<Test,TestVO> mapObj;
    private Set<Test> setList;
    private CopyVO copy;
	// ... get、set、toString 略
}
  1. 测试源类型:Test
public class Test implements Comparable<Test>{
    private String name;
    public Test() {}
    public Test(String name) {
        this.name = name;
    }
    @Override
    public int compareTo(Test o) {
        return this.name.compareTo(o.name);
    }
	// ... get、set、toString 略
}
  1. 测试目标类型:TestVO
public class TestVO implements Comparable<TestVO>{
    private String name;
    @Override
    public int compareTo(TestVO o) {
        return this.name.compareTo(o.name);
    }
	// ... get、set、toString 略
}
  1. 测试Main方法
public class Main {
    public static void main(String[] args) {
        Copy copy = new Copy();
        // 基本类型
        copy.setA(1);
        copy.setB(10.2);
        copy.setC("ABC");
        copy.setD(new Date());
        // 数组
        copy.setE(new int[]{10, 20, 30});
        // 自定义对象、数组
        copy.setTest(new Test("你好"));
        copy.setTests(new Test[]{new Test("Hello")});
        // 列表
        copy.setF(new LinkedList<>(Collections.singletonList(new Test("test"))));

        // Set集合
        TreeSet treeSet = new TreeSet<Test>();
        treeSet.add(new Test("Set集合测试"));
        copy.setSetList(treeSet);
        // Map集合
        Map<Integer, String> map = new HashMap<>();
        map.put(200, "OK");
        map.put(404, "error");
        copy.setMap(map);
        // Map集合(key,value为自定义对象)
        Map<Test,Test> mapObj = new TreeMap<>();
        mapObj.put(new Test("map测试"),new Test("map测试"));
        copy.setMapObj(mapObj);
        // 对象自己,测试层级关系
        Copy subCopy = new Copy();
        subCopy.setC("子对象测试");
        Copy subSubCopy = new Copy();
        subSubCopy.setC("子对象的子对象测试");
        subCopy.setCopy(subSubCopy);
        copy.setCopy(subCopy);


        CopyVO copyVO = new CopyVO();
        long start = System.currentTimeMillis();
        // 工具包调用复制
        BeanUtil.copyProperties(copy, copyVO);
        long end = System.currentTimeMillis();
        System.out.println(copy);
        System.out.println();
        System.out.println(copyVO);
        System.out.println("耗时:"+(end-start)+" ms");
    }
}

结果:

Copy{a=1, b=10.2, c='ABC', d=Fri Jul 08 09:53:54 CST 2022, test=Test{name='你好'}, tests=[Test{name='Hello'}], e=[10, 20, 30], f=[Test{name='test'}], map={404=error, 200=OK}, mapObj={Test{name='map测试'}=Test{name='map测试'}}, setList=[Test{name='Set集合测试'}], copy=Copy{a=null, b=0.0, c='子对象测试', d=null, test=null, tests=null, e=null, f=null, map=null, mapObj=null, setList=null, copy=Copy{a=null, b=0.0, c='子对象的子对象测试', d=null, test=null, tests=null, e=null, f=null, map=null, mapObj=null, setList=null, copy=null}}}

CopyVO{a=1, b=10.2, c='ABC', d=Fri Jul 08 09:53:54 CST 2022, test=TestVO{name='你好'}, tests=[TestVO{name='Hello'}], e=[10, 20, 30], f=[TestVO{name='test'}], map={404=error, 200=OK}, mapObj={Test{name='map测试'}=TestVO{name='map测试'}}, setList=[Test{name='Set集合测试'}], copy=CopyVO{a=null, b=0.0, c='子对象测试', d=null, test=null, tests=null, e=null, f=null, map=null, mapObj=null, setList=null, copy=CopyVO{a=null, b=0.0, c='子对象的子对象测试', d=null, test=null, tests=null, e=null, f=null, map=null, mapObj=null, setList=null, copy=null}}}
耗时:42 ms

对于以上各种类型的测试,测试结果平均耗时仅在50ms左右,还算可观。

ItVuer - 免责声明 - 关于我们 - 联系我们

本网站信息来源于互联网,如有侵权请联系:561261067@qq.com

桂ICP备16001015号