开发中,操作属性时,经常遇到下面这种情况:

public static void main(String[] args) {
        //tony 是新转学的学生,mike 是老生
        Student mike = new Student("Mike",12,"四年二班","Kite","1.4","40","合肥市蜀山区");
        Student tony = new Student("Tony",14,null,null,"1.5","50","合肥市包河区");
 
        // 将 tony 转到了 mike 所在的班级
        tony.setClassName(mike.getClassName());
        tony.setTeacherName(mike.getTeacherName());
 
        // 结果:Student (studentName=Tony, studentAge=14, className = 四年二班,teacherName=Kite, height=1.5, weight=50, homeAddress = 合肥市包河区)
        System.out.println(tony.toString());
    }

上面简单设置两个属性看上去还好,但是如果几十条甚至上百条属性要变,一个一个 set 看上去会很糟糕

下面我们对比一下几个第三方工具中对于属性 copy 的使用,可以借鉴一下:

import com.example.demo.java.other.domain.Student;
import com.example.demo.java.other.domain.Teacher;
import org.apache.commons.beanutils.BeanUtils;
import org.modelmapper.Conditions;
import org.modelmapper.ModelMapper;
import org.springframework.context.annotation.Bean;
//import org.springframework.beans.BeanUtils;
 
/**
 * <p>
 * <code>PropertiesCopyTest</code>
 * </p>
 * Description:java 对象拷贝
 * 注意事项:
 * 使用 spring 的 BeanUtils 不用抛异常,而使用 Apache 的 BeanUtils 必须抛异常(反射),否则编译报错
 * 使用 BeanUtils 的 copyProperties 时,如果实体 B 想要 copy 实体 A,而实体 A 中某些和 B 相同的字段是 null 时,
 *    也会被 copy 过去,导致实体 B 本身存在的数据丢失,此时可以考虑使用 modelMapper 工具
 *
 * @author Mcchu
 * @date 2017/10/13 12:07
 */
public class PropertiesCopyTest {
 
    public static void main(String[] args) {
        // Tony 是新转来的学生,还没有分配班级和老师,下面我们要将他分到和 mike 一个班
        Student mike = mike();
        Student tony = tony();
 
        // 1. 使用 spring 自带的工具,tony 的属性被全部覆盖了,这不是我们想要的
        //BeanUtils.copyProperties(mike,tony);
        // 结果失败:Student (name=Mike, age=12, className = 四年二班,teacherName=Kite, height=1.4, weight=40, homeAddress = 合肥市蜀山区)
        //System.out.println(tony.toString());
 
        try {
            // 2. 使用 apache 工具,将属性一次性全部地 copy 到 tony 上,可以发现 tony 的属性被全部覆盖了,这也不是我们想要的
            //BeanUtils.copyProperties(tony,mike);
            // 结果失败:Student (name=Mike, age=12, className = 四年二班,teacherName=Kite, height=1.4, weight=40, homeAddress = 合肥市蜀山区)
            //System.out.println(tony.toString());
 
            // 3. 使用 apache 工具,退而求其次,我们将属性一个一个地 copy 到 tony 的属性上,这样是可以的
            //BeanUtils.copyProperty( tony, "className", mike.getClassName() );
            //BeanUtils.copyProperty( tony, "teacherName", mike.getTeacherName() );
            // 结果正确:Student (name=Tony, age=14, className = 四年二班,teacherName=Kite, height=1.5, weight=50, homeAddress = 合肥市包河区)
            //System.out.println(tony.toString());
        }catch (Exception e){
            e.printStackTrace();
        }
 
 
        // 4. 我们反过来想,如果将 tony 的属性先覆盖到 mike 的属性上,这里的覆盖有个关键性条件,即只覆盖存在数据的字段,如果为 null 时,不做覆盖操作,此时得到的 mike 属性不就是 tony 需要的真实属性吗?
        //ModelMapper modelMapper = new ModelMapper();
        //modelMapper.getConfiguration().setPropertyCondition(Conditions.isNotNull());
        //modelMapper.map(tony,mike);
        //tony = mike;
        // 结果正确:Student (name=Tony, age=14, className = 四年二班,teacherName=Kite, height=1.5, weight=50, homeAddress = 合肥市包河区)
        //System.out.println(tony.toString());
 
        // 5. 假如我们可以拿得到 kite 老师的属性,而老师的属性里又存在 tony 需要的 className 和 teacherName,那么我们直接 copyProperties 就好了
        try {
            Teacher kite = kite();
            BeanUtils.copyProperties(tony,kite); // 此处等同于 org.springframework.beans.BeanUtils.copyProperties (kite,tony);
            // 结果正确:Student (studentName=Tony, studentAge=14, className = 四年二班,teacherName=Kite, height=1.5, weight=50, homeAddress = 合肥市包河区)
            System.out.println(tony.toString());
        }catch (Exception e){
            e.printStackTrace();
        }
    }
 
    private static Student mike(){
        return new Student("Mike",12,"四年二班","Kite","1.4","40","合肥市蜀山区");
    }
 
    private static Student tony(){
        return new Student("Tony",14,null,null,"1.5","50","合肥市包河区");
    }
 
    private static Teacher kite(){
        return new Teacher("Kite",36,"四年二班");
    }
}

上面 5 种方式中,后 3 种是可以实现正确结果的

附录:Student 实体类和 Teacher 实体类

import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
 
/**
 * <p>
 * <code>Teacher</code>
 * </p>
 * Description:
 *
 * @author Mcchu
 * @date 2017/10/13 13:34
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Teacher {
 
    private String teacherName;
 
    private Integer teacherAge;
 
    private String className;
}
import lombok.AllArgsConstructor;
import lombok.Data;
import lombok.NoArgsConstructor;
 
/**
 * <p>
 * <code>Student</code>
 * </p>
 * Description:
 *
 * @author Mcchu
 * @date 2017/10/13 12:07
 */
@Data
@AllArgsConstructor
@NoArgsConstructor
public class Student {
 
    private String studentName;
 
    private Integer studentAge;
 
    private String className;
 
    private String teacherName;
 
    private String height;
 
    private String weight;
 
    private String homeAddress;
}
更新于 阅读次数

请我喝[茶]~( ̄▽ ̄)~*

Jalen Chu 微信支付

微信支付

Jalen Chu 支付宝

支付宝

Jalen Chu 公众号

公众号