好得很程序员自学网

<tfoot draggable='sEl'></tfoot>

java 如何复制非空对象属性值

java 复制 非空对象 属性值

很多时候,我们需要通过对象拷贝,比如说VO类与数据库实体bean类、更新时非空对象不更新,对同一对象不同数据分开存储等

用于对象拷贝,spring 和 Apache都提供了相应的工具类方法,BeanUtils.copyProperties

但是对于非空属性拷贝就需要自己处理了

在这里借用spring中org.springframework.beans.BeanUtils类提供的方法

copyProperties(Object source, Object target, String... ignoreProperties)

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

/**

      * Copy the property values of the given source bean into the given target bean,

      * ignoring the given "ignoreProperties".

      * <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.

      * <p>This is just a convenience method. For more complex transfer needs,

      * consider using a full BeanWrapper.

      * @param source the source bean

      * @param target the target bean

      * @param ignoreProperties array of property names to ignore

      * @throws BeansException if the copying failed

      * @see BeanWrapper

      */

     public static void copyProperties(Object source, Object target, String... ignoreProperties) throws BeansException {

         copyProperties(source, target, null , ignoreProperties);

 

/**

      * 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

      * @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 {

 

         Assert.notNull(source, "Source must not be null" );

         Assert.notNull(target, "Target must not be null" );

 

         Class<?> actualEditable = target.getClass();

         if (editable != null ) {

             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);

                         }

                     }

                 }

             }

         }

     }

然后封装一下得到以下方法

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

/**

      * @author zml2015

      * @Email zhengmingliang911@gmail测试数据

      * @Time 2017年2月14日 下午5:14:25

      * @Description <p>获取到对象中属性为null的属性名  </P>

      * @param source 要拷贝的对象

      * @return

      */

     public static String[] getNullPropertyNames(Object source) {

         final BeanWrapper src = new BeanWrapperImpl(source);

         java.beans.PropertyDescriptor[] pds = src.getPropertyDescriptors();

 

         Set<String> emptyNames = new HashSet<String>();

         for (java.beans.PropertyDescriptor pd : pds) {

             Object srcValue = src.getPropertyValue(pd.getName());

             if (srcValue == null )

                 emptyNames.add(pd.getName());

         }

         String[] result = new String[emptyNames.size()];

         return emptyNames.toArray(result);

     }

 

     /**

      * @author zml2015

      * @Email zhengmingliang911@gmail测试数据

      * @Time 2017年2月14日 下午5:15:30

      * @Description <p> 拷贝非空对象属性值 </P>

      * @param source 源对象

      * @param target 目标对象

      */

     public static void copyPropertiesIgnoreNull(Object source, Object target) {

         BeanUtils.copyProperties(source, target, getNullPropertyNames(source));

     }

测试方法就不提供了,自行测试即可

如果项目中使用的框架有Hibernate的话,则可以通过在实体类上添加下面两条注解

?

1

2

@DynamicInsert ( true )

@DynamicUpdate ( true )

如果想对该注解进一步了解的话,那么可以去 官网看英文文档 ,文档解释的很清楚,在此不再赘述了

java对象属性复制的几种方式

1.使用java反射机制

获取对象的属性和get、set方法进行复制;

2.使用spring-beans5.0.8包中的BeanUtils类

?

1

2

3

4

import org.springframework.beans.BeanUtils;

SourceObject sourceObject = new SourceObject();

TargetObject targetObject = new TargetObject();

BeanUtils.copyProperties(sourceObject, targetObject);

3.使用cglib3.2.8包中的net.sf.cglib.beans.BeanCopier类

?

1

2

3

4

5

6

7

import net.sf.cglib.beans.BeanCopier;

import net.sf.cglib.core.Converter;

SourceObject sourceObject = new SourceObject();

TargetObject targetObject = new TargetObject();

BeanCopier beanCopier = BeanCopier.create(SourceObject. class , TargetObject. class , true );--第三个参数表示是否使用转换器, false 表示不使用, true 表示使用

Converter converter = new CopyConverter();--自定义转换器

beanCopier.copy(sourceObject, targetObject, converter);

转换器(当源对象属性类型与目标对象属性类型不一致时,使用转换器):

?

1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

import net.sf.cglib.core.Converter;

import org.apache测试数据mons.lang3.StringUtils;

import java.math.BigDecimal;

import java.util.Date;

/**

  * Created by asus on 2019/7/12.

  */

public class CopyConverter implements Converter {

     @Override

     public Object convert(Object value, Class target, Object context) {

         {

             String s = value.toString();

             if (target.equals( int . class ) || target.equals(Integer. class )) {

                 return Integer.parseInt(s);

             }

             if (target.equals( long . class ) || target.equals(Long. class )) {

                 return Long.parseLong(s);

             }

             if (target.equals( float . class ) || target.equals(Float. class )) {

                 return Float.parseFloat(s);

             }

             if (target.equals( double . class ) || target.equals(Double. class )) {

                 return Double.parseDouble(s);

             }

             if (target.equals(Date. class )){

                 while (s.indexOf( "-" )> 0 ){

                     s = s.replace( "-" , "/" );

                 }

                 return   new Date(s);

             }

             if (target.equals(BigDecimal. class )){

                 if (!StringUtils.isEmpty(s)&&!s.equals( "NaN" )){

                     return   new BigDecimal(s);

                 }

             }

             return value ;

         }

     }

}

4.使用spring-core5.0.8包

中的org.springframework.cglib.beans.BeanCopier类(用法与第三种一样)

?

1

2

3

4

5

6

7

import org.springframework.cglib.beans.BeanCopier;

import org.springframework.cglib.core.Converter;

SourceObject sourceObject = new SourceObject();

TargetObject targetObject = new TargetObject();

Converter converter = new SpringCopyConverter();

BeanCopier beanCopier = BeanCopier.create(SourceObject. class , TargetObject. class , true );

beanCopier.copy(sourceObject, targetObject, converter);

经过循环复制测试(源对象与目标对象各160个属性):

第一种:Java反射通过判断属性类型,常用类型的属性值都能复制,但是不优化的前提下效率最慢; 第二种:属性类型不同时无法复制,且效率相对较慢; 第三种:耗时最少,不使用转换器时,属性类型不同时无法复制,使用转换器后,耗时会相对变长; 第四种:与第三种相似,但是耗时相对较长;

以上为个人经验,希望能给大家一个参考,也希望大家多多支持。

原文链接:https://alianga.blog.csdn.net/article/details/55192785

查看更多关于java 如何复制非空对象属性值的详细内容...

  阅读:43次