在開發中經常需要將PO、VO、DTO、DO相互轉換,如果一個個set將十分麻煩,現在也有很成熟的轉換工具類,例如dozer,本人日常開發也會使用這個工具。出於技癢,於是自己開始研究利用反射實現轉換工具。
2020/3/10版:
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
/**
* 利用反射原理的對象轉換類
*/
public class BeanUtils {
private static final String GET = "get";
private static final String SET = "set";
/**
* 淺複製
*
* @param from 轉換對象
* @param to 目標對象
* @param <T> 返回對象
* @return
*/
public static <T> T covert(T from, T to) {
System.out.println("-----------開始轉換----------");
Class<?> fromClass = from.getClass();
Class<?> toClass = to.getClass();
Method[] toClassMethods = toClass.getMethods();
//遍歷to含有的方法
for (Method method : toClassMethods) {
String methodName = method.getName();
// 如果該方法是set方法
if (methodName.startsWith("set")) {
try {
// 從from 獲取對應的get方法
Method getMethod = fromClass.getDeclaredMethod(methodName.replace("set", "get"));
// 執行get方法獲取from的值
Object value = getMethod.invoke(from);
// 執行set方法設置to的值
method.invoke(to, value);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
System.out.println("-----------轉換完成----------");
return to;
}
}
public static void main(String[] args) {
List<Integer> list = new ArrayList<>();
list.add(1);
list.add(2);
list.add(3);
UserEntity userEntity = new UserEntity();
userEntity.setId(1);
userEntity.setName("張三");
userEntity.setPassword("123admin");
userEntity.setSex("男");
userEntity.setUsername("user");
userEntity.setList(list);
System.out.println(userEntity);
UserVO covert = (UserVO) BeanUtils.covert(userEntity, new UserVO());
System.out.println(covert);
list.add(4);
System.out.println("------------修改原本的list後---------");
System.out.println(covert);
}
輸出:
這個版本是我的第一版,目前實現了屬性的淺複製,可以看到例子中list如果後面修改,會影響到轉換後vo的list屬性,原因是隻實現了淺複製。本來想利用clone克隆實現深複製的。但是發現 Object value= getMethod.invoke(from); 我想不出如何調用將value強轉回原本類型,唉還是對反射機制不夠了解....待了解後在進行進一步補充。但是日常開發中大多數不會出現轉換之後還需要修改原本pojo屬性的場景。
2020/3/25
這裏採用了取巧的方式,直接將原本的對象先深克隆,就不需要一步步判斷是否需要對當前值進行克隆。
深克隆的方法有兩種:1.序列化與反序列化生成對象。2.所有引用類型都得實現Cloneable。
這次採用了序列化與反序列化的思路,實現了對象的深克隆。(因爲序列化的話比較現實,所有的引用類型都得實現Cloneable就太麻煩了)
//實現序列化接口
public class UserEntity implements Serializable {
private Integer id;
private String username;
private String password;
private String name;
private String sex;
private List<Integer> list;
}
/**
* 深拷貝
*
* @param from
* @param to
* @param <T>
* @return
*/
public static <T> T depthCovert(T from, T to) {
Class<?> fromClass = from.getClass();
Class<?> toClass = to.getClass();
System.out.println("-----------開始轉換----------");
System.out.println("被轉換的對象類型" + fromClass);
System.out.println("待轉換的對象類型" + toClass);
if (!(fromClass instanceof Serializable)) {
throw new RuntimeException("轉換對象沒有實現Serializable");
}
try {
from = deepClone(from);
} catch (Exception e) {
throw new RuntimeException("深拷貝對象異常");
}
Method[] toClassMethods = toClass.getMethods();
//遍歷to含有的方法
for (Method method : toClassMethods) {
String methodName = method.getName();
// 如果該方法是set方法
if (methodName.startsWith("set")) {
try {
// 從from 獲取對應的get方法
Method getMethod = fromClass.getDeclaredMethod(methodName.replace("set", "get"));
// 執行get方法獲取from的值
Object invoke = getMethod.invoke(from);
// 執行set方法設置to的值
method.invoke(to, invoke);
} catch (NoSuchMethodException e) {
e.printStackTrace();
} catch (IllegalAccessException e) {
e.printStackTrace();
} catch (InvocationTargetException e) {
e.printStackTrace();
}
}
}
System.out.println("-----------轉換完成----------");
return to;
}
private static <T> T deepClone(T t) throws IOException, ClassNotFoundException {
System.out.println("-----------開始克隆----------");
// 序列化
ByteArrayOutputStream bos = new ByteArrayOutputStream();
ObjectOutputStream oos = new ObjectOutputStream(bos);
oos.writeObject(t);
// 反序列化
ByteArrayInputStream bis = new ByteArrayInputStream(bos.toByteArray());
ObjectInputStream ois = new ObjectInputStream(bis);
t = (T) ois.readObject();
System.out.println("-----------結束克隆----------");
return t;
}
可以看到,userVO裏的list和原本的list已經不是同一個List了,深拷貝成功。
有什麼問題可以評論或者私信我,每日在線解(LIAO)疑(SAO)。
我是大誌,一位準備996的卑微碼農🐶,覺得好用記得點贊收藏!!!