BeanUtils.copyProperties()介绍及开发常见问题小tip

1.BeanUtils.copyProperties()介绍

BeanUtils.copyProperties()是Apache Commons BeanUtils包中提供的一个静态方法,用于快速地从一个Java Bean对象复制属性到另一个Java Bean对象。该方法基于反射机制,通过获取源对象和目标对象的属性名称,然后直接设置目标对象的属性值,从而实现属性的复制。

以下是BeanUtils.copyProperties()的用法示例:

import org.apache.commons.beanutils.BeanUtils;

public class Main {
    public static void main(String[] args) {
        Person source = new Person("John", 30);
        Person target = new Person();

        BeanUtils.copyProperties(source, target);

        System.out.println(target.getName()); // 输出: John
        System.out.println(target.getAge()); // 输出: 30
    }
}

class Person {
    private String name;
    private int age;

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }
}

在这个例子中,我们首先创建了一个Person对象source,然后创建了一个空的Person对象target。接着,我们调用BeanUtils.copyProperties()方法,将source对象的属性复制到target对象中。

2、使用BeanUtils.copyProperties(source, target)时的注意事项

  最近总结了以下几个方面:

我将针对这三点注意事项分别给出例子说明。

  1. 目标类和源类的属性都要提供get/set方法

    如果目标类和源类的属性没有提供get/set方法,那么在使用BeanUtils.copyProperties()方法时,就会抛出NoSuchMethodException异常。这是因为BeanUtils.copyProperties()方法依赖于get/set方法来获取和设置属性值。

    例如,考虑以下两个类:

    class Source {
        private String name;
        private int age;
    }
    
    class Target {
        private String name;
        private int age;
    }
    

    在这两个类中,虽然属性名相同,但是它们都没有提供get/set方法。如果我们尝试使用BeanUtils.copyProperties()方法来复制属性值,就会得到如下错误信息:

    java.lang.NoSuchMethodException: Source.<init>()
    

    这是因为BeanUtils.copyProperties()方法试图通过构造函数来创建目标对象,但由于源类没有提供无参构造函数,所以抛出了这个异常。

    解决这个问题的方法很简单,只需为每个类添加get/set方法即可:

    class Source {
        private String name;
        private int age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    
    class Target {
        private String name;
        private int age;
    
        public String getName() {
            return name;
        }
    
        public void setName(String name) {
            this.name = name;
        }
    
        public int getAge() {
            return age;
        }
    
        public void setAge(int age) {
            this.age = age;
        }
    }
    

    现在,我们可以安全地使用BeanUtils.copyProperties()方法来复制属性值了。

  2. 使用这个方法的前提是要确保两个类中的属性名相同,且不会轻易变化

    如果目标类和源类的属性名不一致,或者属性名经常发生变化,那么在使用BeanUtils.copyProperties()方法时,可能会导致复制过程失败或产生意想不到的结果。

    例如,考虑以下两个类:

    class Source {
        private String firstName;
        private String lastName;
    }
    
    class Target {
        private String fullName;
    }
    

    在这两个类中,虽然属性名都是字符串类型,但是它们的含义不同。如果我们尝试使用BeanUtils.copyProperties()方法来复制属性值,就会得到如下错误信息:

    java.lang.IllegalArgumentException: Property 'fullName' not found in source object of type 'Source'
    

    这是因为BeanUtils.copyProperties()方法无法找到源对象中的fullName属性,从而抛出了这个异常。

    解决这个问题的方法也很简单,只需确保源类和目标类的属性名完全匹配即可:

    class Source {
        private String firstName;
        private String lastName;
    }
    
    class Target {
        private String firstName;
        private String lastName;
    }
    

    现在,我们可以安全地使用BeanUtils.copyProperties()方法来复制属性值了。

  3. 只能针对基本数据类型的属性进行复制,自定义类需要单独处理,不能直接复制

    BeanUtils.copyProperties()方法只能处理基本数据类型的属性,对于自定义类的属性,它并不能直接复制。如果我们尝试复制自定义类的属性,就会得到如下错误信息:

    java.lang.ClassCastException: java.lang.String cannot be cast to com.example.MyClass
    

    这是因为BeanUtils.copyProperties()方法试图将源对象中的属性值转换为目标对象的属性类型,但由于属性类型不匹配,所以抛出了这个异常。

    例如,考虑以下两个类:

    class Source {
        private MyClass myObject;
    }
    
    class Target {
        private MyClass myObject;
    }
    
    class MyClass {
        private String value;
    }
    

    在这两个类中,虽然属性类型都是MyClass,但是它们的内部结构不同。如果我们尝试使用BeanUtils.copyProperties()方法来复制属性值,就会得到上述错误信息。

3.用法拓展:深浅拷贝

BeanUtils.copyProperties()这个方法实际上支持两种不同的属性复制策略:浅拷贝和深拷贝。

  • 浅拷贝:只复制对象的引用,而不复制对象本身。这意味着如果源对象和目标对象指向同一个内存地址,那么它们实际上是共享同一个对象的副本。在BeanUtils.copyProperties()方法中,默认采用的是浅拷贝策略。

  • 深拷贝:不仅复制对象的引用,还复制对象本身。这意味着即使源对象和目标对象指向同一个内存地址,它们也是各自独立的对象。要实现深拷贝,我们需要显式地指定BeanUtils.copyProperties()方法的第三个参数为true

在实际应用中,选择哪种方式取决于具体的需求。例如,如果你希望在复制过程中创建一个新的对象实例,那么就需要进行深拷贝。反之,如果你只需要复制对象的引用,那么浅拷贝就足够了。

举个例子,假设我们有两个类PersonEmployee,其中EmployeePerson的一个子类。现在我们想要从一个Person对象复制到一个Employee对象中,同时保持Employee对象的独立性。

class Person {
    private String name;
    private int age;

    // getter and setter methods
}

class Employee extends Person {
    private double salary;

    // getter and setter methods
}

public class Main {
    public static void main(String[] args) {
        Person person = new Person();
        person.setName("John");
        person.setAge(30);

        Employee employee = new Employee();
        BeanUtils.copyProperties(person, employee); // shallow copy

        // 修改person对象的属性
        person.setName("Jane");
        person.setAge(35);

        // 查看employee对象是否受到影响
        System.out.println(employee.getName()); // 输出: John
        System.out.println(employee.getAge()); // 输出: 30
    }
}

在这个例子中,我们首先创建了一个Person对象并设置其属性。然后,我们创建了一个Employee对象,并使用BeanUtils.copyProperties()方法进行浅复制。接着,我们修改了person对象的属性,但是当我们查看employee对象的属性时,发现它们并没有被更新。这是因为BeanUtils.copyProperties()方法默认采用浅拷贝策略,它只复制了对象的引用,而没有复制对象本身。

如果我们想要进行深拷贝,可以使用BeanUtils.copyProperties()方法的另一个变体BeanUtils.copyProperties(source, target, true),其中第三个参数true表示进行深拷贝。这样,即使我们修改了person对象的属性,employee对象也会相应地更新。

4、总结

总的来说,BeanUtils.copyProperties()方法提供了快速复制Java Bean对象属性的便捷方式,但在使用时需要注意各种注意事项。只有正确理解并遵循这些原则,才能确保程序的正确性和稳定性。
本篇遇到一些注意事项总结如下:

1.目标类和源类的属性都要提供get/set方法,否则无法复制值
2.使用这个方法,前提是要确保两个类中的属性名相同,且不会轻易变化,否则还是建议使用get/set老老实实赋值
3.只能针对基本数据类型的属性进行复制,自定义类需要单独处理,不能直接复制。

日后也会再加以补充。

  • 26
    点赞
  • 11
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值