利用Java反射机制实现对象相同字段的复制操作

一、如何实现不同类型对象之间的复制问题?

1、为什么会有这个问题?

近来在进行一个项目开发的时候,为了隐藏后端数据库表结构、同时也为了配合给前端一个更友好的API接口文档(swagger API文档),我采用POJO来对应数据表结构,使用VO来给传递前端要展示的数据,同时使用DTO来进行请求参数的封装。以上是一个具体的场景,可以发现这样子一个现象:POJO、VO、DTO对象是同一个数据的不同视图,所以会有很多相同的字段,由于不同的地方使用不同的对象,无可避免的会存在对象之间的值迁移问题,迁移的一个特征就是需要迁移的值字段相同。字段相同,于是才有了不同对象之间进行值迁移复制的问题。

2、现有的解决方法

一个一个的get出来后又set进去。这个方法无可避免会增加很多的编码复杂度,还是一些很没有营养的代码,看多了还会烦,所以作为一个有点小追求的程序员都没有办法忍受这种摧残。

使用别人已经存在的工具。在spring包里面有一个可以复制对象属性的工具方法,可以进行对象值的复制,下一段我们详细去分析它的这个工具方法。

自己动手丰衣足食。自己造工具来用,之所以自己造工具不是因为喜欢造工具,而是现有的工具没办法解决自己的需求,不得已而为之。

二、他山之石可以攻玉,详谈spring的对象复制工具

1、看看spring的对象复制工具到底咋样?

类名:org.springframework.beans.BeanUtils

这个类里面所有的属性复制的方法都调用了同一个方法,我们就直接分析这个原始的方法就行了。

 /**
 * 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的父类或其实现的接口,用于控制属性复制的范围
 * @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();//获取目标对象的动态类型
 //下面判断的意图在于控制属性复制的范围
 if (editable != null) {
 //必须是target对象的父类或者其实现的接口类型,相当于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());
 //如果没办法从原对象里面读出属性也没有必要继续了
 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、对复制工具的一些看法和总结

总结上一段代码的分析,我们发现spring自带的工具有以下特点:

它名副其实的是在复制属性,而不是字段!!

它可以通过一个目标对象的父类或者其实现的接口来控制需要复制属性的范围

很贴心的可以忽略原对象的某些字段,可以通过2的方法忽略某些目标对象的字段

但是,这远远不够!!!我需要如下的功能:

复制对象的字段,而不是属性,也就是说我需要一个更暴力的复制工具。

我需要忽略原对象的某些字段,同时也能够忽略目标对象的某些字段。

我的项目还需要忽略原对象为null的字段和目标对象不为null的字段

带着这三个需求,开始我的工具制造。

三、自己动手丰衣足食

1、我需要解析字节码

为了避免对字节码的重复解析,使用缓存来保留解析过的字节码解析结果,同时为了不让这个工具太占用内存,使用软引用来进行缓存,上代码:

 /*
  ******************************************************
  * 基础的用于支持反射解析的解析结果缓存,使用软引用实现
  ******************************************************
  */
 private static final Map<Class<?>,SoftReference<Map<String,Field>>> resolvedClassCache = new ConcurrentHashMap<>();

 /**
  * 同步解析字节码对象,将解析的结果放入到缓存 1、解析后的字段对象全部 accessAble
  * 1、返回的集合不支持修改,要修改请记得自己重新建一个复制的副本
  * @param sourceClass:需要解析的字节码对象
  */
 @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
 public static Map<String,Field> resolveClassFieldMap(final Class<?> sourceClass){

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

  //判断是否已经被初始化
  if(softReference == null || softReference.get() == null){

   //对同一个字节码对象的解析是同步的,但是不同字节码对象的解析是并发的,因为字节码对象只有一个
   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);
      }
     }

     //设置为不变Map,这个肯定是不能够改的啊!所以取的时候需要重新构建一个map
     fieldMap = Collections.unmodifiableMap(fieldMap);

     softReference = new SoftReference<>(fieldMap);

     /*
     更新缓存,将解析后的数据加入到缓存里面去
      */
     resolvedClassCache.put(sourceClass,softReference);

     return fieldMap;
    }
   }
  }

  /*
  运行到这里来的时候要么早就存在,要么就是已经被其他的线程给初始化了
   */
  return softReference.get();
 }

2、我需要能够进行对象的复制,基本方法

 /**
  * 进行属性的基本复制操作
  * @param source:源对象
  * @param sourceFieldMap:原对象解析结果
  * @param target:目标对象
  * @param targetFieldMap:目标对象解析结果
  */
 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、夜深了,准备睡觉了

基于这两个方法,对其进行封装,实现了我需要的功能,并且在项目中运行目前还没有bug,应该可以直接用在生产环境,各位看官觉得可以可以拿来试一试哦!!

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 {

 /*
  ******************************************************
  * 基础的用于支持反射解析的解析结果缓存,使用软引用实现
  ******************************************************
  */
 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());

  //获取全部的字段名称,因为原数据没办法修改,所以需要重新建立一个集合来进行判断
  Set<String> allFieldNames = new HashSet<>(classFieldMap.keySet());

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

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

 /*
  ***************************************************************
  * 复制一个对象的相关工具方法,注意事项如下:
  * 1、只能复制字段名称相同且数据类型兼容的字段数据
  * 2、只能复制这个对象实际类(运行时动态类型)里面声明的各种字段
  ***************************************************************
  */

 /**
  * 将一个对象里面字段相同、类型兼容的数据复制到另外一个对象去
  * 1、只复制类的运行时类型的声明的全部访问权限的字段
  * @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())));
 }

 /**
  * 除实现 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())));
 }

 /**
  * 除实现 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())));
 }

 /**
  * 除实现 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);
 }

 /**
  * 除实现 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);
 }

 /*
  ******************************
  * 内部工具方法或者内部兼容方法
  ******************************
  */

 /**
  * 同步解析字节码对象,将解析的结果放入到缓存 1、解析后的字段对象全部 accessAble
  * 1、返回的集合不支持修改,要修改请记得自己重新建一个复制的副本
  * @param sourceClass:需要解析的字节码对象
  */
 @SuppressWarnings("SynchronizationOnLocalVariableOrMethodParameter")
 public static Map<String,Field> resolveClassFieldMap(final Class<?> sourceClass){

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

  //判断是否已经被初始化
  if(softReference == null || softReference.get() == null){

   //对同一个字节码对象的解析是同步的,但是不同字节码对象的解析是并发的
   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);
      }
     }

     //设置为不变Map
     fieldMap = Collections.unmodifiableMap(fieldMap);

     softReference = new SoftReference<>(fieldMap);

     /*
     更新缓存,将解析后的数据加入到缓存里面去
      */
     resolvedClassCache.put(sourceClass,softReference);

     return fieldMap;
    }
   }
  }
  /*
  运行到这里来的时候要么早就存在,要么就是已经被其他的线程给初始化了
   */
  return softReference.get();
 }

 /**
  * 确保正确的从缓存里面获取解析后的数据
  * 1、返回的集合不支持修改,要修改请记得自己重新建一个复制的副本
  * @param sourceClass:需要解析的字节码对象
  */
 public static Map<String,Field> getClassFieldMapWithCache(Class<?> sourceClass){

  //查看缓存里面有没有已经解析完毕的现成的数据
  SoftReference<Map<String,Field>> softReference = resolvedClassCache.get(sourceClass);

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

   //解析字节码对象
   return resolveClassFieldMap(sourceClass);
  }else {

   //从缓存里面正确的取出数据
   return softReference.get();
  }
 }

 /**
  * 将一个可变参数集合转换为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:原对象解析结果
  * @param target:目标对象
  * @param targetFieldMap:目标对象解析结果
  */
 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里相同的字段自动填充

最近因为经常会操作讲两个JavaBean之间相同的字段互相填充,所以就写了个偷懒的方法。记录一下

/**
	 * 将两个JavaBean里相同的字段自动填充
	 * @param dto 参数对象
	 * @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反射机制实现对象相同字段的复制操作就是小编分享给大家的全部内容了,希望能给大家一个参考,也希望大家多多支持我们。

(0)

相关推荐

  • Java 反射机制原理与用法详解

    本文实例讲述了Java 反射机制原理与用法.分享给大家供大家参考,具体如下: 反射反射,程序员的快乐! 1.什么是反射? Java反射就是在运行状态中,对于任意一个类,都能够知道这个类的所有属性和方法:对于任意一个对象,都能够调用它的任意方法和属性:并且能改变它的属性.而这也是Java被视为动态(或准动态,为啥要说是准动态,因为一般而言的动态语言定义是程序运行时,允许改变程序结构或变量类型,这种语言称为动态语言.从这个观点看,Perl,Python,Ruby是动态语言,C++,Java,C#不是

  • 使用java反射将结果集封装成为对象和对象集合操作

    java反射机制是什么 反射机制是在运行状态中,可以知道任何一个类的属性和方法,并且调用类的属性和方法: 反射机制能够做什么 1.判断运行对象的所属类 2.构造任意一个类的对象 3.获取任意一个类的属性和方法 4.调用任意属性和方法 5.生成动态代理 利用反射将结果集封装成为对象或者集合(实测可用) package coral.base.util; import java.beans.IntrospectionException; import java.beans.PropertyDescri

  • Java 通过反射给实体类赋值操作

    表单提交这个方法是挺方便的,但在java来说就显得有些麻烦了, 怎么个麻烦呢,就是当你字段多的时候,你就得一个一个的获取其对应的值,这样代码量就多了起来,其代码量不说,维护也是一个问题. 所以就有了这样一个类,只需把request和实体类对象传进去就行了, 这样就会得到一个有值的实体类对象 下面是代码示例 import java.lang.reflect.Field; import java.lang.reflect.Method; import java.sql.Date; import ja

  • java反射机制给实体类相同字段自动赋值实例

    一.封装一个工具类 1.简易版 package net.aexit.construct.acceptance.websky.utils; import java.lang.reflect.Field; import java.lang.reflect.Method; import java.util.HashMap; import java.util.Iterator; import java.util.Map; public class ClassReflection { /** * @par

  • 利用Java反射机制实现对象相同字段的复制操作

    一.如何实现不同类型对象之间的复制问题? 1.为什么会有这个问题? 近来在进行一个项目开发的时候,为了隐藏后端数据库表结构.同时也为了配合给前端一个更友好的API接口文档(swagger API文档),我采用POJO来对应数据表结构,使用VO来给传递前端要展示的数据,同时使用DTO来进行请求参数的封装.以上是一个具体的场景,可以发现这样子一个现象:POJO.VO.DTO对象是同一个数据的不同视图,所以会有很多相同的字段,由于不同的地方使用不同的对象,无可避免的会存在对象之间的值迁移问题,迁移的一

  • java 利用java反射机制动态加载类的简单实现

    如下所示: ////////////////// Load.java package org.bromon.reflect; import java.util.ArrayList; import java.util.List; public class Load implements Operator { @Override public List<?> act(List<?> params) { // TODO Auto-generated method stub List<

  • 利用java反射机制调用类的私有方法(推荐)

    试想一下,如果你可以轻易地调用一个类的私有方法,那么是不是说你的封装都失效了?最近在看java的反射机制,发现居然可以利用java的反射机制去调用其他类的私有方法,至于这能干什么,那就见人见智了.. 我写的一段简易实例代码如下: import java.lang.reflect.InvocationTargetException; import java.lang.reflect.Method; /** * @author thomaslwq * @version 创建时间:Sep 4, 201

  • 利用java反射机制实现自动调用类的简单方法

    1. 新建TestServlet类 package com.yanek.test; import java.io.IOException; import java.lang.reflect.Method; import javax.servlet.ServletException; import javax.servlet.http.HttpServlet; import javax.servlet.http.HttpServletRequest; import javax.servlet.ht

  • Java反射机制原理、Class获取方式以及应用场景详解

    目录 学习背景 一.Java反射机制是什么? 1.1 反射原理 1.2 反射例子 二.Java反射机制中获取Class的三种方式及区别? 2.1 Class的几种获取方式 2.2 代码演示几种方式的区别 三.Java反射机制的应用场景有哪些? 3.1 应用场景 3.2 简单工厂模式优化 3.2.1 什么是简单工厂模式? 3.2.2 简单工厂模式有什么用? 3.2.3 如何实现简单工程模式? 3.2.4 简单工厂模式优化 3.2.5 简单工厂模式再次优化 3.3 代理模式中的动态代理实现 3.3.

  • Java反射机制的学习总结

    一.什么是反射机制 简单的来说,反射机制指的是程序在运行时能够获取自身的信息.在java中,只要给定类的名字,那么就可以通过反射机制来获得类的所有信息. 二.哪里用到反射机制 有些时候,我们用过一些知识,但是并不知道它的专业术语是什么,在刚刚学jdbc时用过一行代码, Class.forName("com.mysql.jdbc.Driver.class").newInstance();但是那时候只知道那行代码是生成驱动对象实例,并不知道它的具体含义.听了反射机制这节课后,才知道,原来这

  • Java反射机制详解

    本文较为详细的分析了Java反射机制.分享给大家供大家参考,具体如下: 一.预先需要掌握的知识(java虚拟机) java虚拟机的方法区: java虚拟机有一个运行时数据区,这个数据区又被分为方法区,堆区和栈区,我们这里需要了解的主要是方法区.方法区的主要作用是存储被装载的类 的类型信息,当java虚拟机装载某个类型的时候,需要类装载器定位相应的class文件,然后将其读入到java虚拟机中,紧接着虚拟机提取class 中的类型信息,将这些信息存储到方法区中.这些信息主要包括: 1.这个类型的全

  • java反射机制的一些学习心得小结

    概述 之前在了解Spring的类加载机制的时候,了解了java的反射机制.但是,我对反射理解一直不深.也一直有点疑惑:Spring为什么利用反射创建对象?直接new对象和依靠反射创建对象有什么区别?什么是动态加载类? 什么是反射? 要想知道反射到底是什么,首先需要知道java的类加载和对象创建的机制. 当我们写完一个java文件的时候,后缀是.java.在我们利用IDE执行java文件的时候,其实IDE也帮我们运行了javac,即java编译器.编译器会将.java文件编译成.class文件.j

  • java反射机制最详解

    目录 java反射机制 什么是反射? 反射的功能: 反射常用类: 1.Class枚举类 2.Constructor构造器 3.Method方法类 4.Field变量类 反射运行指示图 通过反射获取对象 总结 java反射机制 什么是反射? 在java开发中有一个非常重要的概念就是java反射机制,也是java的重要特征之一.反射的概念是由Smith在1982年首次提出的,主要是指程序可以访问.检测和修改它本身状态或行为的一种能力,通过反射可以调用私有方法和私有属性,大部分框架也都是运用反射原理的

随机推荐