標籤:方法 setter 接收 運行時 世界 miss mapper 吐槽 應該
最近在寫java代碼的時候,需要進行對象轉換,由於欄位名存在不同,BeanUtils無法滿足需求,所以想到了java世界有沒有類似C#的AutoMapper庫,找到了 ModelMapper
以官方的Getting Started為例
來源物件
// Assume getters and setters on each classclass Order { Customer customer; Address billingAddress;}class Customer { Name name;}class Name { String firstName; String lastName;}class Address { String street; String city;}
目標對象
// Assume getters and settersclass OrderDTO { String customerFirstName; String customerLastName; String billingStreet; String billingCity;}
由於以上對象的定義符合約定的規則,可以不需要任何配置,完成類型的轉換
ModelMapper modelMapper = new ModelMapper();OrderDTO orderDTO = modelMapper.map(order, OrderDTO.class);
重點來了,有時候我們需要轉換的是整個List,總不至於讓我們對列表中每個對象逐個進行轉換,幸好,官方也提供了相應的api
ModelMapper modelMapper = new ModelMapper();modelMapper.createTypeMap(Order.class, OrderDTO.class);List<Order> orderList = new ArrayList<>();//TODO: orderList添加元素Type listType = new TypeToken<List<OrderDTO>>(){}.getType();List<OrderDTO> dtoList = modelMapper.map(orderList, listType);
看起來好像一切正常,程式運行出來的結果也是正確的,但是,細看最後一行代碼
List<OrderDTO> dtoList = modelMapper.map(orderList, listType);
modelMapper.map方法接收的2個參數類型,一個是 List<Order>, 另外一個是 Type, 編譯器無法在編譯時間刻知道Type中包含具體什麼類型,它是怎麼知道這個方法返回的類型是 List<OrderDTO>?於是我將這一行代碼改成了
List<Order> dtoList = modelMapper.map(orderList, listType);
編譯器沒有警告和錯誤提示,運行時查看dtoList中對象的結構為OrderDTO,查看ModelMapper的源碼,發現
public class ModelMapper { public <D> D map(Object source, Type destinationType){...}
從方法的簽名上看,D的類型是無法確定的(雖然方法內部可以通過讀取Type中包含的類型,構造出對象),也就是說,唯一能夠確定的是方法返回的是Object,通過IDEA的智能提示,這個方法確實返回的是Object, 那麼為什麼將Object賦值給List對象的時候,編譯器沒有警告呢?
我們用java和C#對這種泛型寫法做一個簡單的對比測試
java代碼
public class Mapper { public <D> D convert(Object obj) { return (D)obj; }}
C#代碼
public class Mapper{ public T convert(Object obj){ return (T)obj; }}
對java代碼進行編譯,順利通過,相反,對C#的代碼進行編譯,未通過,有錯誤提示,“Error CS0246: The type or namespace name ‘T‘ could not be found (are you missing a using directive or an assembly reference?) (CS0246) ”,明確指出T的類型未找到,
從我個人的理解,java中的泛型由於運行時的類型擦除,只在編譯時間起到類型檢查的作用,但是上述的寫法做到了讓編譯器的類型檢查失效,根本就不應該讓這樣的代碼通過編譯,編譯器的語義分析存在缺陷。
另外吐槽一下java的類型書寫,C#通過AutoMapper對列表的轉換可以寫成
List<OrderDTO> dtoList = mapper.map<List<OrderDTO>>(orderList);
但是java中沒有List<OrderDTO>.class的寫法,是很膈應的事情
由於剛從C#入java,理解會有偏差,歡迎指正
從一段java泛型代碼發現java編譯器的缺陷