java反射效率 同名字段赋值

  • 项目又做回了web端,遇到了一个之前听过问题
  • 项目接口接受的对象为req对象,数据库使用的为dto对象,有大量名称相同的字段,需要进行类型转换。同名字段赋值
  • 每一次都重复20多次的set方法显得很蠢,之前朋友说用反射方法 效率很低闲来无事实现了一下
package *.biz.utils;


import lombok.extern.slf4j.Slf4j;
import org.apache.ibatis.executor.loader.cglib.CglibProxyFactory;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;

/**
 *
 * 将一个类型T的对象 相同属性赋值给 类型R的对象
 * @author 16
 */
@Slf4j
public class TransformUtils<T,R> {

//    publice <T,R> T

    public static <T,R>  R transform(T src, R dest) {
        Class<?> srcClass = src.getClass();
        Field[] srcFields = srcClass.getDeclaredFields();
        Class<?> destClass = dest.getClass();
        Field[] destFields = destClass.getDeclaredFields();
        Object o;
        destClass.getDeclaredFields();
//        遍历src的属性 如果不为null
        for (Field f : srcFields) {
//            获取src的值
            f.setAccessible(true);
            Object fieldValue = null;
            try {
                fieldValue = f.get(src);
            } catch (IllegalAccessException e) {
                e.printStackTrace();
            }
            if (fieldValue == null) {
                log.info(f.getName() + "属性不存在忽略");
                continue;
            }
            Method[] methods = destClass.getMethods();
//          就尝试赋值给dest
            try {
                String name = f.getName();

                StringBuilder replaceName = new StringBuilder(name).replace(0, 1, String.valueOf(Character.toUpperCase(name.charAt(0))));
                Method method = dest.getClass().getMethod("set" + replaceName, f.getType());
                method.invoke(dest, fieldValue);
//              方法不存在会抛出异常 所以此处存在

            } catch (NoSuchMethodException | IllegalAccessException | InvocationTargetException e) {
                log.info(f.getName() + "set方法不存在忽略");
                continue;
            }
            log.info(f.getName() + " 替换为"+ fieldValue + " 成功");
        }
        return dest;
    }

    public static void main(String[] args) {
        AppApplyReq appApplyReq = new AppApplyReq();
        appApplyReq.setId(1234);
        long startTime = System.nanoTime();
        for (int i = 0; i < 10000; i++) {
            AppApplyDO appApplyDO = new AppApplyDO();
            appApplyReq = transform(appApplyDO, appApplyReq);
            log.info(appApplyDO.getId() + "");
            log.info(appApplyReq.getId() + "");
            log.info("usedTime=" + (System.nanoTime() - startTime));
        }
        startTime = System.nanoTime();
        for (int i = 0; i < 10000; i++) {
            AppApplyDO appApplyDO1 = appApplyReq.forAppApplyDo();
        }
        log.info("usedTime=" + (System.nanoTime() - startTime));
    }
}

16:43:50.384 [main] INFO *.utils.TransformUtils - usedTime=4153631688
16:43:50.387 [main] INFO *.utils.TransformUtils - usedTime=3009321
  • 如果没写bug的话 效率应该相差了1000倍

  • 本来以为反射多次使用的话效率应该会有优化 实际测试过程中发现并没有

  • 然后 为了偷懒 代码自动生成类

    /**
     *
     * @param srcClass
     * @param destClass
     * @return
     */
    public static String buildCode(Class<?> srcClass,Class<?> destClass) {
//        Class<?> srcClass = src.getClass();
        Field[] srcFields = srcClass.getDeclaredFields();
//        Class<?> destClass = dest.getClass();
        Field[] destFields = destClass.getDeclaredFields();
        String srcClassName = srcClass.getSimpleName();
        String destClassName = destClass.getSimpleName();
        String srcObjectName = firstCharLower(srcClassName);
        String destObjectName = firstCharLower(destClassName);
        StringBuilder stringBuilder = new StringBuilder();
        stringBuilder.append("public " + destClassName +" transform" + srcClassName + "2" + destClassName
                +"(" + srcClassName + " " +srcObjectName +", "  + destClassName + " " + destObjectName + "){\n");
        for (Field f : srcFields) {
            String fieldName = f.getName();
            String upperFieldName = firstCharUpper(fieldName);
            String srcGetMethodName = "get" + upperFieldName;
            String destSetMethodName = "set" + upperFieldName;
            try {
                srcClass.getMethod(srcGetMethodName);
                destClass.getMethod(destSetMethodName, f.getType());
                stringBuilder
                        .append("\t")
                        .append(destObjectName)
                        .append(".")
                        .append(destSetMethodName)
                        .append("(")
                        .append(srcObjectName)
                        .append(".")
                        .append(srcGetMethodName)
                        .append("());\n");
            } catch (NoSuchMethodException e) {
                log.info(fieldName + "没有匹配的方法!");
            }
            log.info(fieldName + "匹配成功!");
        }
        stringBuilder.append("}\n");
        System.out.println(stringBuilder.toString());
        return stringBuilder.toString();
    }


    public static String firstCharUpper(String str) {
        char[] chars = str.toCharArray();
        chars[0] = Character.toUpperCase(chars[0]);
        return String.valueOf(chars);
    }

    public static String firstCharLower(String str) {
        char[] chars = str.toCharArray();
        chars[0] = Character.toLowerCase(chars[0]);
        return String.valueOf(chars);
    }
自动生成的代码示例
public AppApplyDO transformAppApplyReq2AppApplyDO(AppApplyReq appApplyReq, AppApplyDO appApplyDO){
	appApplyDO.setId(appApplyReq.getId());
	appApplyDO.setOrgId(appApplyReq.getOrgId());
	appApplyDO.setOrgCode(appApplyReq.getOrgCode());
	appApplyDO.setOrgName(appApplyReq.getOrgName());
}
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值