文章《用Spring的BeanUtils前,建議你先了解這幾個坑》里面,作者最后得到了這幾個結論:
1.Spring得BeanUtils得CopyProperties方法需要對應得屬性有getter和setter方法;
2.如果存在屬性完全相同得內部類,但是不是同一個內部類,即分別屬於各自得內部類,則Spring會認為屬性不同,不會Copy;
3.泛型只在編譯期起作用,不能依靠泛型來做運行期得限制;
4.最后,Spring和Apache得copy屬性得方法源和目的參數得位置正好相反,所以導包和調用得時候需要注意以下。
在這里,我們今天重點說的是第二點,第一點是因為用反射拿到set和get方法再去拿屬性值和設置屬性值的,不懂反射的人可以自行百度下。第三和第四點很簡單了應該是不需要解釋的。
驗證
首先,我把我自己的測試代碼也貼出來:
@Data
public class TestEntity{
private Integer age;
private String name;
private Inner inner;
@Data
public static class Inner{
private Integer a;
public Inner(Integer a){
this.a = a;
}
}
}
@Data
public class TestVO{
private Integer age;
private String name;
private Inner inner;
@Data
public static class Inner{
private Integer a;
public Inner(Integer a){
this.a = a;
}
}
}
public class Main{
public static void main(String args[]){
TestEntity entity = new TestEntity();
entity.setAge(1);
entity.setName("hehe");
entity.setInner(new TestEntity.Inner(1));
TestVO vo = new TestVO();
BeanUtils.copyProperties(entity,vo);
System.out.println(vo.toString());
}
}
以上就是我得三個類,是不是超級簡單,比如工作中將entity轉vo,就有這種使用場景,運行main方法,測試結果和那個作者得出的第二點的結論是一樣的,b對象里面的inner是null!
但是這個是為什么呢?這個是BUG嗎?這個也是我今天要說的重點。
內部類
我們知道,java給我們提供了內部類這樣的東東,但是java的內部類,它其實只是java的一個語法糖而已(不知道什么是語法糖的請自行百度),那么我們定義得兩個JAVA類里面的Inner的真面目到底是怎樣的呢?
來到編譯后的.class文件目錄下,我們可以看到編譯后得.class文件:
哈哈,不知道讀者到這里是不是能明白些什么了呢?為什么經過BeanUtils.CopyProperties(entity,vo)之后,vo里面的inner還是null,因為TestEntity.java和TestVO.java里面的Inner在編譯之后的class名字都不一樣(代表加載到虛擬機之后的地址不同),怎么可能拷貝成功呢?
那么問題來了哈,我們怎樣用才能讓其拷貝成功呢?我稍微修改了下我的代碼如下:
@Data
public class TestVO{
private Integer age;
private String name;
private TestEntity.Inner inner;
}
僅僅是把Inner變為了TestEntity.Inner,刪掉了沒引用得內部類Inner,Main.java不變,然后運行結果如下:
可以看到,b對象里面的inner被成功拷貝過來。
此時編譯后得class文件也由5個變為了4個