欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

利用Java反射機制實現(xiàn)對象相同字段的復制操作

 更新時間:2020年08月21日 08:53:51   作者:一只有著大國夢的兔子  
這篇文章主要介紹了利用Java反射機制實現(xiàn)對象相同字段的復制操作,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧

一、如何實現(xiàn)不同類型對象之間的復制問題?

1、為什么會有這個問題?

近來在進行一個項目開發(fā)的時候,為了隱藏后端數(shù)據(jù)庫表結(jié)構(gòu)、同時也為了配合給前端一個更友好的API接口文檔(swagger API文檔),我采用POJO來對應(yīng)數(shù)據(jù)表結(jié)構(gòu),使用VO來給傳遞前端要展示的數(shù)據(jù),同時使用DTO來進行請求參數(shù)的封裝。以上是一個具體的場景,可以發(fā)現(xiàn)這樣子一個現(xiàn)象:POJO、VO、DTO對象是同一個數(shù)據(jù)的不同視圖,所以會有很多相同的字段,由于不同的地方使用不同的對象,無可避免的會存在對象之間的值遷移問題,遷移的一個特征就是需要遷移的值字段相同。字段相同,于是才有了不同對象之間進行值遷移復制的問題。

2、現(xiàn)有的解決方法

一個一個的get出來后又set進去。這個方法無可避免會增加很多的編碼復雜度,還是一些很沒有營養(yǎng)的代碼,看多了還會煩,所以作為一個有點小追求的程序員都沒有辦法忍受這種摧殘。

使用別人已經(jīng)存在的工具。在spring包里面有一個可以復制對象屬性的工具方法,可以進行對象值的復制,下一段我們詳細去分析它的這個工具方法。

自己動手豐衣足食。自己造工具來用,之所以自己造工具不是因為喜歡造工具,而是現(xiàn)有的工具沒辦法解決自己的需求,不得已而為之。

二、他山之石可以攻玉,詳談spring的對象復制工具

1、看看spring的對象復制工具到底咋樣?

類名:org.springframework.beans.BeanUtils

這個類里面所有的屬性復制的方法都調(diào)用了同一個方法,我們就直接分析這個原始的方法就行了。

 /**
 * Copy the property values of the given source bean into the given target bean.
 * <p>Note: The source and target classes do not have to match or even be derived
 * from each other, as long as the properties match. Any bean properties that the
 * source bean exposes but the target bean does not will silently be ignored.
 * @param source the source bean:也就是說要從這個對象里面復制值出去
 * @param target the target bean:出去就是復制到這里面來
 * @param editable the class (or interface) to restrict property setting to:這個類對象是target的父類或其實現(xiàn)的接口,用于控制屬性復制的范圍
 * @param ignoreProperties array of property names to ignore:需要忽略的字段
 * @throws BeansException if the copying failed
 * @see BeanWrapper
 */
 private static void copyProperties(Object source, Object target, Class<?> editable, String... ignoreProperties)
 throws BeansException {

 //這里在校驗要復制的對象是不可以為null的,這兩個方法可是會報錯的??!
 Assert.notNull(source, "Source must not be null");
 Assert.notNull(target, "Target must not be null");
 //這里和下面的代碼就有意思了
 Class<?> actualEditable = target.getClass();//獲取目標對象的動態(tài)類型
 //下面判斷的意圖在于控制屬性復制的范圍
 if (editable != null) {
 //必須是target對象的父類或者其實現(xiàn)的接口類型,相當于instanceof運算符
 if (!editable.isInstance(target)) {
 throw new IllegalArgumentException("Target class [" + target.getClass().getName() +
  "] not assignable to Editable class [" + editable.getName() + "]");
 }
 actualEditable = editable;
 }
 //不得不說,下面這段代碼乖巧的像綿羊,待我們來分析分析它是如何如何乖巧的
 PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);//獲取屬性描述,描述是什么?描述就是對屬性的方法信息的封裝,好乖。
 List<String> ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);

 //重頭戲開始了!開始進行復制了
 for (PropertyDescriptor targetPd : targetPds) {
 //先判斷有沒有寫方法,沒有寫方法我也就沒有必要讀屬性出來了,這個懶偷的真好!
 Method writeMethod = targetPd.getWriteMethod();
 //首先,沒有寫方法的字段我不寫,乖巧撒?就是說你不讓我改我就不改,讓我忽略我就忽略!
 if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
 PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
 //如果沒辦法從原對象里面讀出屬性也沒有必要繼續(xù)了
 if (sourcePd != null) {
  Method readMethod = sourcePd.getReadMethod();
  //這里就更乖巧了!寫方法不讓我寫我也不寫?。?!
  if (readMethod != null &&
  ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {
  try {
  //這里就算了,來都來了,就乖乖地進行值復制吧,別搞東搞西的了
  if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
  readMethod.setAccessible(true);
  }
  Object value = readMethod.invoke(source);
  if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
  writeMethod.setAccessible(true);
  }
  writeMethod.invoke(target, value);
  }
  catch (Throwable ex) {
  throw new FatalBeanException(
   "Could not copy property '" + targetPd.getName() + "' from source to target", ex);
  }
  }
 }
 }
 }
 }

2、對復制工具的一些看法和總結(jié)

總結(jié)上一段代碼的分析,我們發(fā)現(xiàn)spring自帶的工具有以下特點:

它名副其實的是在復制屬性,而不是字段!!

它可以通過一個目標對象的父類或者其實現(xiàn)的接口來控制需要復制屬性的范圍

很貼心的可以忽略原對象的某些字段,可以通過2的方法忽略某些目標對象的字段

但是,這遠遠不夠!??!我需要如下的功能:

復制對象的字段,而不是屬性,也就是說我需要一個更暴力的復制工具。

我需要忽略原對象的某些字段,同時也能夠忽略目標對象的某些字段。

我的項目還需要忽略原對象為null的字段和目標對象不為null的字段

帶著這三個需求,開始我的工具制造。

三、自己動手豐衣足食

1、我需要解析字節(jié)碼

為了避免對字節(jié)碼的重復解析,使用緩存來保留解析過的字節(jié)碼解析結(jié)果,同時為了不讓這個工具太占用內(nèi)存,使用軟引用來進行緩存,上代碼:

 /*
  ******************************************************
  * 基礎(chǔ)的用于支持反射解析的解析結(jié)果緩存,使用軟引用實現(xiàn)
  ******************************************************
  */
 private static final Map<Class<?>,SoftReference<Map<String,Field>>> resolvedClassCache = new ConcurrentHashMap<>();
 
 /**
  * 同步解析字節(jié)碼對象,將解析的結(jié)果放入到緩存 1、解析后的字段對象全部 accessAble
  * 1、返回的集合不支持修改,要修改請記得自己重新建一個復制的副本
  * @param sourceClass:需要解析的字節(jié)碼對象
  */
 @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
 public static Map<String,Field> resolveClassFieldMap(final Class<?> sourceClass){

  SoftReference<Map<String,Field>> softReference = resolvedClassCache.get(sourceClass);

  //判斷是否已經(jīng)被初始化
  if(softReference == null || softReference.get() == null){

   //對同一個字節(jié)碼對象的解析是同步的,但是不同字節(jié)碼對象的解析是并發(fā)的,因為字節(jié)碼對象只有一個
   synchronized(sourceClass){

    softReference = resolvedClassCache.get(sourceClass);

    if(softReference == null || softReference.get() == null){

    //采用:<字段名稱,字段對象> 來記錄解析結(jié)果
     Map<String,Field> fieldMap = new HashMap<>();

     /*
     Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this
     Class object. This includes public, protected, default access, and private fields, but excludes inherited fields
     */
     Field[] declaredFields = sourceClass.getDeclaredFields();

     if(declaredFields != null && declaredFields.length > 0){

      for(Field field : declaredFields){

       /*
       Set the accessible flag for this object to the indicated boolean value.
       */
       field.setAccessible(true);
   //字段名稱和字段對象
       fieldMap.put(field.getName(),field);
      }
     }

     //設(shè)置為不變Map,這個肯定是不能夠改的啊!所以取的時候需要重新構(gòu)建一個map
     fieldMap = Collections.unmodifiableMap(fieldMap);

     softReference = new SoftReference<>(fieldMap);

     /*
     更新緩存,將解析后的數(shù)據(jù)加入到緩存里面去
      */
     resolvedClassCache.put(sourceClass,softReference);

     return fieldMap;
    }
   }
  }

  /*
  運行到這里來的時候要么早就存在,要么就是已經(jīng)被其他的線程給初始化了
   */
  return softReference.get();
 }

2、我需要能夠進行對象的復制,基本方法

 /**
  * 進行屬性的基本復制操作
  * @param source:源對象
  * @param sourceFieldMap:原對象解析結(jié)果
  * @param target:目標對象
  * @param targetFieldMap:目標對象解析結(jié)果
  */
 public static void copyObjectProperties(Object source,Map<String,Field> sourceFieldMap,Object target,Map<String,Field> targetFieldMap){

  //進行屬性值復制
  sourceFieldMap.forEach(
    (fieldName,sourceField) -> {

     //查看目標對象是否存在這個字段
     Field targetField = targetFieldMap.get(fieldName);

     if(targetField != null){

      try{
       //對目標字段進行賦值操作
       targetField.set(target,sourceField.get(source));
      }catch(IllegalAccessException e){
       e.printStackTrace();
      }
     }
    }
  );
 }

3、夜深了,準備睡覺了

基于這兩個方法,對其進行封裝,實現(xiàn)了我需要的功能,并且在項目中運行目前還沒有bug,應(yīng)該可以直接用在生產(chǎn)環(huán)境,各位看官覺得可以可以拿來試一試哦?。?/p>

4、完整的代碼(帶注釋:需要自取,無外部依賴,拿來即用)

package edu.cqupt.demonstration.common.util;

import java.lang.ref.SoftReference;
import java.lang.reflect.Field;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * 反射的工具集,主要用于對對象的復制操作
 */
public class ReflectUtil {

 /*
  ******************************************************
  * 基礎(chǔ)的用于支持反射解析的解析結(jié)果緩存,使用軟引用實現(xiàn)
  ******************************************************
  */
 private static final Map<Class<?>,SoftReference<Map<String,Field>>> resolvedClassCache = new ConcurrentHashMap<>();

 /*
  ****************************************
  * 獲取一個對象指定條件字段名稱的工具方法
  ****************************************
  */

 /**
  * 獲取一個對象里面字段為null的字段名稱集合
  */
 public static String[] getNullValueFieldNames(Object source){

  //非空校驗:NullPointerException
  Objects.requireNonNull(source);

  Class<?> sourceClass = source.getClass();

  //從緩存里面獲取,如果緩存里面沒有就會進行第一次反射解析
  Map<String,Field> classFieldMap = getClassFieldMapWithCache(sourceClass);

  List<String> nullValueFieldNames = new ArrayList<>();

  classFieldMap.forEach(
    (fieldName,field) -> {

     try{
      //挑選出值為null的字段名稱
      if(field.get(source) == null){
       nullValueFieldNames.add(fieldName);
      }
     }catch(IllegalAccessException e){
      e.printStackTrace();
     }
    }
  );

  return nullValueFieldNames.toArray(new String[]{});
 }

 /**
  * 獲取一個對象里面字段不為null的字段名稱集合
  */
 public static String[] getNonNullValueFieldNames(Object source){

   //非空校驗
  Objects.requireNonNull(source);

  //獲取空值字段名稱
  String[] nullValueFieldNames = getNullValueFieldNames(source);

  Map<String,Field> classFieldMap = getClassFieldMapWithCache(source.getClass());

  //獲取全部的字段名稱,因為原數(shù)據(jù)沒辦法修改,所以需要重新建立一個集合來進行判斷
  Set<String> allFieldNames = new HashSet<>(classFieldMap.keySet());

  //移除掉值為null的字段名稱
  allFieldNames.removeAll(Arrays.asList(nullValueFieldNames));

  return allFieldNames.toArray(new String[]{});
 }

 /*
  ***************************************************************
  * 復制一個對象的相關(guān)工具方法,注意事項如下:
  * 1、只能復制字段名稱相同且數(shù)據(jù)類型兼容的字段數(shù)據(jù)
  * 2、只能復制這個對象實際類(運行時動態(tài)類型)里面聲明的各種字段
  ***************************************************************
  */

 /**
  * 將一個對象里面字段相同、類型兼容的數(shù)據(jù)復制到另外一個對象去
  * 1、只復制類的運行時類型的聲明的全部訪問權(quán)限的字段
  * @param source:從這個對象復制
  * @param target:復制到這個對象來
  */
 public static void copyPropertiesSimple(Object source,Object target){

  copyObjectProperties(
    source,new HashMap<>(getClassFieldMapWithCache(source.getClass())),
    target,new HashMap<>(getClassFieldMapWithCache(target.getClass())));
 }

 /**
  * 除實現(xiàn) copyPropertiesSimple 的功能外,會忽略掉原對象的指定字段的復制
  * @param ignoreFieldNames:需要忽略的原對象字段名稱集合
  */
 public static void copyPropertiesWithIgnoreSourceFields(Object source,Object target,String ...ignoreFieldNames){

  Map<String,Field> sourceFieldMap = new HashMap<>(getClassFieldMapWithCache(source.getClass()));

  filterByFieldName(sourceFieldMap,ignoreFieldNames);

  copyObjectProperties(source,sourceFieldMap,target,new HashMap<>(getClassFieldMapWithCache(target.getClass())));
 }

 /**
  * 除實現(xiàn) copyPropertiesSimple 的功能外,會忽略掉原對象字段值為null的字段
  */
 public static void copyPropertiesWithNonNullSourceFields(Object source,Object target){

  Map<String,Field> sourceFieldMap = new HashMap<>(getClassFieldMapWithCache(source.getClass()));

  filterByFieldValue(source,sourceFieldMap,true);

  copyObjectProperties(source,sourceFieldMap,target,new HashMap<>(getClassFieldMapWithCache(target.getClass())));
 }

 /**
  * 除實現(xiàn) copyPropertiesSimple 的功能外,會忽略掉目標對象的指定字段的復制
  * @param ignoreFieldNames:需要忽略的原對象字段名稱集合
  */
 public static void copyPropertiesWithIgnoreTargetFields(Object source,Object target,String ...ignoreFieldNames){

  Map<String,Field> targetFieldMap = new HashMap<>(getClassFieldMapWithCache(target.getClass()));

  filterByFieldName(targetFieldMap,ignoreFieldNames);

  copyObjectProperties(source,new HashMap<>(getClassFieldMapWithCache(source.getClass())),target,targetFieldMap);
 }

 /**
  * 除實現(xiàn) copyPropertiesSimple 的功能外,如果目標對象的屬性值不為null將不進行覆蓋
  */
 public static void copyPropertiesWithTargetFieldNonOverwrite(Object source,Object target){

  Map<String,Field> targetFieldMap = new HashMap<>(getClassFieldMapWithCache(target.getClass()));

  filterByFieldValue(target,targetFieldMap,false);
  copyObjectProperties(source,new HashMap<>(getClassFieldMapWithCache(source.getClass())),target,targetFieldMap);
 }

 /**
  * 進行復制的完全定制復制
  * @param source:源對象
  * @param target:目標對象
  * @param ignoreSourceFieldNames:需要忽略的原對象字段名稱集合
  * @param ignoreTargetFieldNames:要忽略的目標對象字段集合
  * @param isSourceFieldValueNullAble:是否在源對象的字段為null的時候仍然進行賦值
  * @param isTargetFiledValueOverwrite:是否在目標對象的值不為null的時候仍然進行賦值
  */
 public static void copyPropertiesWithConditions(Object source,Object target
   ,String[] ignoreSourceFieldNames,String[] ignoreTargetFieldNames
   ,boolean isSourceFieldValueNullAble,boolean isTargetFiledValueOverwrite){

  Map<String,Field> sourceFieldMap = new HashMap<>(getClassFieldMapWithCache(source.getClass()));
  Map<String,Field> targetFieldMap = new HashMap<>(getClassFieldMapWithCache(target.getClass()));

  if(!isSourceFieldValueNullAble){

   filterByFieldValue(source,sourceFieldMap,true);
  }

  if(!isTargetFiledValueOverwrite){
   filterByFieldValue(target,targetFieldMap,false);
  }

  filterByFieldName(sourceFieldMap,ignoreSourceFieldNames);
  filterByFieldName(targetFieldMap,ignoreTargetFieldNames);
  copyObjectProperties(source,sourceFieldMap,target,targetFieldMap);
 }

 /*
  ******************************
  * 內(nèi)部工具方法或者內(nèi)部兼容方法
  ******************************
  */

 /**
  * 同步解析字節(jié)碼對象,將解析的結(jié)果放入到緩存 1、解析后的字段對象全部 accessAble
  * 1、返回的集合不支持修改,要修改請記得自己重新建一個復制的副本
  * @param sourceClass:需要解析的字節(jié)碼對象
  */
 @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
 public static Map<String,Field> resolveClassFieldMap(final Class<?> sourceClass){

  SoftReference<Map<String,Field>> softReference = resolvedClassCache.get(sourceClass);

  //判斷是否已經(jīng)被初始化
  if(softReference == null || softReference.get() == null){

   //對同一個字節(jié)碼對象的解析是同步的,但是不同字節(jié)碼對象的解析是并發(fā)的
   synchronized(sourceClass){

    softReference = resolvedClassCache.get(sourceClass);
    if(softReference == null || softReference.get() == null){

     Map<String,Field> fieldMap = new HashMap<>();
     /*
     Returns an array of Field objects reflecting all the fields declared by the class or interface represented by this
     Class object. This includes public, protected, default access, and private fields, but excludes inherited fields
     */
     Field[] declaredFields = sourceClass.getDeclaredFields();
     if(declaredFields != null && declaredFields.length > 0){
      for(Field field : declaredFields){
       /*
       Set the accessible flag for this object to the indicated boolean value.
       */
       field.setAccessible(true);
       fieldMap.put(field.getName(),field);
      }
     }

     //設(shè)置為不變Map
     fieldMap = Collections.unmodifiableMap(fieldMap);

     softReference = new SoftReference<>(fieldMap);

     /*
     更新緩存,將解析后的數(shù)據(jù)加入到緩存里面去
      */
     resolvedClassCache.put(sourceClass,softReference);

     return fieldMap;
    }
   }
  }
  /*
  運行到這里來的時候要么早就存在,要么就是已經(jīng)被其他的線程給初始化了
   */
  return softReference.get();
 }

 /**
  * 確保正確的從緩存里面獲取解析后的數(shù)據(jù)
  * 1、返回的集合不支持修改,要修改請記得自己重新建一個復制的副本
  * @param sourceClass:需要解析的字節(jié)碼對象
  */
 public static Map<String,Field> getClassFieldMapWithCache(Class<?> sourceClass){

  //查看緩存里面有沒有已經(jīng)解析完畢的現(xiàn)成的數(shù)據(jù)
  SoftReference<Map<String,Field>> softReference = resolvedClassCache.get(sourceClass);

  //確保classFieldMap的正確初始化和緩存
  if(softReference == null || softReference.get() == null){

   //解析字節(jié)碼對象
   return resolveClassFieldMap(sourceClass);
  }else {

   //從緩存里面正確的取出數(shù)據(jù)
   return softReference.get();
  }
 }

 /**
  * 將一個可變參數(shù)集合轉(zhuǎn)換為List集合,當為空的時候返回空集合
  */
 public static <T> List<T> resolveArrayToList(T ...args){

  List<T> result = new ArrayList<>();
  if(args != null && args.length > 0){
   result = Arrays.asList(args);
  }
  return result;
 }

 /**
  * 進行屬性的基本復制操作
  * @param source:源對象
  * @param sourceFieldMap:原對象解析結(jié)果
  * @param target:目標對象
  * @param targetFieldMap:目標對象解析結(jié)果
  */
 public static void copyObjectProperties(Object source,Map<String,Field> sourceFieldMap,Object target,Map<String,Field> targetFieldMap){

  //進行屬性值復制
  sourceFieldMap.forEach(
    (fieldName,sourceField) -> {

     //查看目標對象是否存在這個字段
     Field targetField = targetFieldMap.get(fieldName);

     if(targetField != null){

      try{
       //對目標字段進行賦值操作
       targetField.set(target,sourceField.get(source));
      }catch(IllegalAccessException e){
       e.printStackTrace();
      }
     }
    }
  );
 }

 /**
  * 忽略掉對象里面的某些字段
  */
 public static void filterByFieldName(Map<String,Field> fieldMap,String ... ignoreFieldNames){

  //需要忽略的對象字段
  List<String> ignoreNames = ReflectUtil.<String>resolveArrayToList(ignoreFieldNames);

  //移除忽略的對象字段
  fieldMap.keySet().removeAll(ignoreNames);
 }

 /**
  * 忽略掉非空的字段或者空的字段
  */
 public static void filterByFieldValue(Object object,Map<String,Field> fieldMap,boolean filterNullAble){

  Iterator<String> iterator = fieldMap.keySet().iterator();
  if(filterNullAble){
   while(iterator.hasNext()){
    try{
     //移除值為null的字段
     if(fieldMap.get(iterator.next()).get(object) == null){
      iterator.remove();
     }
    }catch(IllegalAccessException e){
     e.printStackTrace();
    }
   }
  }else {

   while(iterator.hasNext()){

    try{
     //移除字段不為null的字段
     if(fieldMap.get(iterator.next()).get(object) != null){
      iterator.remove();
     }
    }catch(IllegalAccessException e){
     e.printStackTrace();
    }
   }
  }
 }
}

補充知識:Java將兩個JavaBean里相同的字段自動填充

最近因為經(jīng)常會操作講兩個JavaBean之間相同的字段互相填充,所以就寫了個偷懶的方法。記錄一下

/**
	 * 將兩個JavaBean里相同的字段自動填充
	 * @param dto 參數(shù)對象
	 * @param obj 待填充的對象
	 */
	public static void autoFillEqFields(Object dto, Object obj) {
		try {
			Field[] pfields = dto.getClass().getDeclaredFields();
 
			Field[] ofields = obj.getClass().getDeclaredFields();
 
			for (Field of : ofields) {
				if (of.getName().equals("serialVersionUID")) {
					continue;
				}
				for (Field pf : pfields) {
					if (of.getName().equals(pf.getName())) {
						PropertyDescriptor rpd = new PropertyDescriptor(pf.getName(), dto.getClass());
						Method getMethod = rpd.getReadMethod();// 獲得讀方法
 
						PropertyDescriptor wpd = new PropertyDescriptor(pf.getName(), obj.getClass());
						Method setMethod = wpd.getWriteMethod();// 獲得寫方法
 
						setMethod.invoke(obj, getMethod.invoke(dto));
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}
 
	/**
	 * 將兩個JavaBean里相同的字段自動填充,按指定的字段填充
	 * @param dto
	 * @param obj
	 * @param String[] fields
	 */
	public static void autoFillEqFields(Object dto, Object obj, String[] fields) {
		try {
			Field[] ofields = obj.getClass().getDeclaredFields();
 
			for (Field of : ofields) {
				if (of.getName().equals("serialVersionUID")) {
					continue;
				}
				for (String field : fields) {
					if (of.getName().equals(field)) {
						PropertyDescriptor rpd = new PropertyDescriptor(field, dto.getClass());
						Method getMethod = rpd.getReadMethod();// 獲得讀方法
 
						PropertyDescriptor wpd = new PropertyDescriptor(field, obj.getClass());
						Method setMethod = wpd.getWriteMethod();// 獲得寫方法
 
						setMethod.invoke(obj, getMethod.invoke(dto));
					}
				}
			}
		} catch (Exception e) {
			e.printStackTrace();
		}
	}

但這樣寫不能把父類有的屬性自動賦值所以修改了一下

/**
 * 將兩個JavaBean里相同的字段自動填充
 * @param obj 原JavaBean對象
 * @param toObj 將要填充的對象
 */
 public static void autoFillEqFields(Object obj, Object toObj) {
 try {
 Map<String, Method> getMaps = new HashMap<>();
 Method[] sourceMethods = obj.getClass().getMethods();
 for (Method m : sourceMethods) {
 if (m.getName().startsWith("get")) {
  getMaps.put(m.getName(), m);
 }
 }
 
 Method[] targetMethods = toObj.getClass().getMethods();
 for (Method m : targetMethods) {
 if (!m.getName().startsWith("set")) {
  continue;
 }
 String key = "g" + m.getName().substring(1);
 Method getm = getMaps.get(key);
 if (null == getm) {
  continue;
 }
 // 寫入方法寫入
 m.invoke(toObj, getm.invoke(obj));
 }
 } catch (Exception e) {
 e.printStackTrace();
 }
 }

以上這篇利用Java反射機制實現(xiàn)對象相同字段的復制操作就是小編分享給大家的全部內(nèi)容了,希望能給大家一個參考,也希望大家多多支持腳本之家。

相關(guān)文章

  • 最優(yōu)雅地整合 Spring & Spring MVC & MyBatis 搭建 Java 企業(yè)級應(yīng)用(附源碼)

    最優(yōu)雅地整合 Spring & Spring MVC & MyBatis 搭建 Java 企業(yè)級應(yīng)用(附源碼)

    這篇文章主要介紹了最優(yōu)雅地整合 Spring & Spring MVC & MyBatis 搭建 Java 企業(yè)級應(yīng)用(附源碼),本文給大家介紹的非常詳細,對大家的學習或工作具有一定的參考借鑒價值,需要的朋友可以參考下
    2021-01-01
  • IDEA 2022 CPU占用100%的問題及解決方法

    IDEA 2022 CPU占用100%的問題及解決方法

    這篇文章主要介紹了IDEA 2022 CPU占用100%問題及解決方法,其實解決方法很簡單,只需要禁用三個插件然后重啟idea即可成功解決,需要的朋友可以參考下本文
    2022-08-08
  • Jmeter對響應(yīng)數(shù)據(jù)實現(xiàn)斷言代碼實例

    Jmeter對響應(yīng)數(shù)據(jù)實現(xiàn)斷言代碼實例

    這篇文章主要介紹了Jmeter對響應(yīng)數(shù)據(jù)實現(xiàn)斷言代碼實例,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-09-09
  • Java redisson實現(xiàn)分布式鎖原理詳解

    Java redisson實現(xiàn)分布式鎖原理詳解

    這篇文章主要介紹了Java redisson實現(xiàn)分布式鎖原理詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-02-02
  • hadoop分布式環(huán)境搭建過程

    hadoop分布式環(huán)境搭建過程

    這篇文章主要介紹了hadoop分布式環(huán)境搭建過程,本文圖文并茂給大家介紹的非常詳細,具有一定的參考借鑒價值,需要的朋友可以參考下
    2019-09-09
  • netty中的IO、NIO、AIO使用詳解

    netty中的IO、NIO、AIO使用詳解

    這篇文章主要介紹了netty中的IO、NIO、AIO使用詳解,本文會說明各種IO的特點、分別解決了什么樣的問題做一個分析闡述,并結(jié)合Java代碼例子來輔助理解,像這些的歷史演進和詳細的底層原理網(wǎng)上很多,所以我們只站在應(yīng)用層,使用者的角度去分析,需要的朋友可以參考下
    2023-12-12
  • java如何在應(yīng)用代碼里捕獲線程堆棧

    java如何在應(yīng)用代碼里捕獲線程堆棧

    這篇文章主要為大家介紹了java如何在應(yīng)用代碼里捕獲線程堆棧實現(xiàn)示例,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-12-12
  • ElasticSearch合理分配索引分片原理

    ElasticSearch合理分配索引分片原理

    這篇文章主要介紹了ElasticSearch合理分配索引分片原理,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下
    2020-04-04
  • 修改jvm-sandbox源碼導致線程安全分析

    修改jvm-sandbox源碼導致線程安全分析

    這篇文章主要為大家介紹了修改jvm-sandbox源碼導致線程安全分析,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪
    2023-06-06
  • javaSE中異常如何處理舉例詳解

    javaSE中異常如何處理舉例詳解

    程序運行過程中發(fā)生了不正常的情況,這種不正常的情況叫做異常,下面這篇文章主要給大家介紹了關(guān)于javaSE中異常如何處理的相關(guān)資料,文中通過實例代碼介紹的非常詳細,需要的朋友可以參考下
    2023-01-01

最新評論