spring BeanUtils.copyProperties浅拷贝之特殊的Boolean
背景
在開發過程中, 在數據庫查詢和接口調用過程中,為了隔離,我們往往會將查詢出來的對象(包括數據庫返回和接口返回)和對外提供的實體對象隔離開來。此時就需要把一個對象的屬性拷貝到目標對象中
通常有2種做法:
1、一個一個set b.setField(a.getField());
2、使用拷貝的工具類,比方說 BeanUtils.copyProperties (因為他們的類結構和屬性字段大多是類似的)
對于字段比較多的場景,使用BeanUtils明顯更加簡潔
那么問題來了,
BeanUtils對于對象中包含的對象也能夠幫我們進行拷貝嗎?
如果會進行拷貝,它幫我們做的拷貝是深拷貝還是淺拷貝?
深淺拷貝 的主要區別就是:復制的是引用還是復制的是值。
如果僅僅復制了引用,也就是說,復制之后,原來的變量和新的變量指向同一個地址,彼此之間的操作會互相影響,為 淺拷貝。
而如果是在堆中重新分配內存,擁有不同的地址,但是值是一樣的,復制后的對象與原來的對象是完全隔離,互不影響,就是深拷貝。
BeansUtils 實戰
創建兩個類 Student和Course 以及一個目標類StudentEntity(和Student類除了名字以外其余字段和結構都完全一致)
public class Student {private String name;private Integer age;/*** 是否已畢業* */private Boolean isGraduated;private Course course;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Boolean getGraduated() {return isGraduated;}public void setGraduated(Boolean graduated) {isGraduated = graduated;}public Course getCourse() {return course;}public void setCourse(Course course) {this.course = course;}@Overridepublic String toString() {return "Student{" +"name='" + name + '\'' +", age=" + age +", isGraduated=" + isGraduated +", course=" + course +'}';} public class Course {private String courseName;private Integer score;public String getCourseName() {return courseName;}public void setCourseName(String courseName) {this.courseName = courseName;}public Integer getScore() {return score;}public void setScore(Integer score) {this.score = score;}@Overridepublic String toString() {return "Course{" +"courseName='" + courseName + '\'' +", score=" + score +'}';} }測試類:
public class Test {@org.junit.Testpublic void testCopyStudent(){Student student = new Student();student.setName("chenpp");student.setAge(21);student.setGraduated(true);Course course = new Course();course.setCourseName("Chinese");course.setScore(100);student.setCourse(course);StudentEntity copyStudent = new StudentEntity();BeanUtils.copyProperties(student, copyStudent);System.out.println("拷貝后的對象" + copyStudent);copyStudent.getCourse().setCourseName("Math");System.out.println("修改拷貝后的course,原來的對象" + student);} }
從上面的代碼可以看出,spring-beans提供的BeanUtils.copyProperties對于外層的屬性無論是基本數據類型還是引用數據類型都會進行拷貝,使用的是淺拷貝
Boolean和boolean類型的拷貝
在使用過程中,發現如果Student的isGraduated字段的set方法定義成isGraduated(),那么拷貝就會失敗
public class Student {private String name;private Integer age;/*** 是否已畢業* */private Boolean isGraduated;private Course course;public String getName() {return name;}public void setName(String name) {this.name = name;}public Integer getAge() {return age;}public void setAge(Integer age) {this.age = age;}public Boolean isGraduated() {return isGraduated;}public void setIsGraduated(Boolean isGraduated) {this.isGraduated = isGraduated;} }測試結果: isGraduated字段沒有被拷貝
跟蹤下源碼看看是什么原因?
其源碼路徑如下
BeanUtils.getPropertyDescriptor -->
? ? ?CachedIntrospectionResults.forClass(clazz) -->
? ? ?? ? ? new CachedIntrospectionResults(beanClass) -->
? ? ?? ? ?? ? ? Introspector.getBeanInfo(Class<?> beanClass) -->
? ? ?? ? ?? ? ?? ? ? Introspector.getBeanInfo()
從這里就可以看到,如果屬性是Boolean類型,其read方法需要以getXXX命名,而對于boolean類型,需要以isXX命名
根據class獲取對應的屬性信息之后,會緩存在propertyDescriptorCache里,debug可以看到StudentEntity的isGraduated字段對應的readMethod為空(Student的isGraduated字段對應的readMethod也為空)
總結
BeanUtils.copyProperties主要是通過反射實現的淺拷貝,如果對象都是單一的屬性或者子對象不涉及到改動,可以BeanUtils進行拷貝
在拷貝的時候注意對于Boolean類型字段,其readMethod需要以getXXX來命名
總結
以上是生活随笔為你收集整理的spring BeanUtils.copyProperties浅拷贝之特殊的Boolean的全部內容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: Git之删除本地无用分支
- 下一篇: CentOS报错:“Could not