java反射機制及beanUtils的實現(xiàn)原理分析
1.反射機制說明
Java的反射機制允許程序在運行時檢查和操作類、方法、字段等結構。通過反射,可以動態(tài)地創(chuàng)建對象、調用方法、獲取/設置字段的值,而無需在編譯時確定這些操作。
反射的核心類是java.lang.reflect包中的Method、Field和Constructor等。使用反射需要注意性能開銷和安全性問題。
- 獲取類的Class對象
Class<?> clazz = MyClass.class;
- 實例化對象
MyClass myObject = (MyClass) clazz.getDeclaredConstructor().newInstance();
- 獲取和調用方法
Method method = clazz.getDeclaredMethod("methodName", parameterTypes);
method.setAccessible(true); // 如果方法是private的,需要設置accessible為true
Object result = method.invoke(myObject, args);- 獲取和設置字段值
Field field = clazz.getDeclaredField("fieldName");
field.setAccessible(true); // 如果字段是private的,需要設置accessible為true
Object value = field.get(myObject);
field.set(myObject, newValue);- 操作構造函數
Constructor<?> constructor = clazz.getDeclaredConstructor(parameterTypes); constructor.setAccessible(true); // 如果構造函數是private的,需要設置accessible為true MyClass myObject = (MyClass) constructor.newInstance(args);
2.VO,DTO,PO的說明
VO(Value Object)值對象
VO就是展示用的數據,不管展示方式是網頁,還是客戶端,還是APP,只要是這個東西是讓人看到的,這就叫VO,這個大家都很理解,反正就是我們的接口返回給前端的對象都是用VO來返回,跟DTO不一樣的是,VO是我們返回給前端,DTO是我們從前端接收的時候用的,即一個是入參,一個是返回結果
DTO(Data Transfer Object)數據傳輸對象
這個傳輸通常指的前后端之間的傳輸
DTO是一個比較特殊的對象,他有兩種存在形式:
- 一種是前端和后端交互所使用的對象
- 另一種是微服務之間的一種傳輸對象,我們一般也是用DTO來進行傳輸
PO(Persistant Object)持久對象
PO比較好理解,簡單說PO就是數據庫中的記錄,一個PO的數據結構對應著庫中表的結構,表中的一條記錄就是一個PO對象,通常PO里面除了get,set之外沒有別的方法,對于PO來說,數量是相對固定的,一定不會超過數據庫表的數量,等同于BO,這倆概念是一致的
3.beanUtils的實現(xiàn)原理
在后端的各個層中進行數據傳輸時,經常使用beanUtils進行bean的拷貝,其實現(xiàn)原理就是通過java的放射機制實現(xiàn)。
package org.springframework.beans;
private static void copyProperties(Object source, Object target, @Nullable Class<?> editable, @Nullable String... ignoreProperties) throws BeansException {
Assert.notNull(source, "Source must not be null");
Assert.notNull(target, "Target must not be null");
Class<?> actualEditable = target.getClass();
if (editable != null) {
if (!editable.isInstance(target)) {
throw new IllegalArgumentException("Target class [" + target.getClass().getName() + "] not assignable to Editable class [" + editable.getName() + "]");
}
actualEditable = editable;
}
PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);
List<String> ignoreList = ignoreProperties != null ? Arrays.asList(ignoreProperties) : null;
PropertyDescriptor[] var7 = targetPds;
int var8 = targetPds.length;
for(int var9 = 0; var9 < var8; ++var9) {
PropertyDescriptor targetPd = var7[var9];
Method writeMethod = targetPd.getWriteMethod();
if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {
PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());
if (sourcePd != null) {
Method readMethod = sourcePd.getReadMethod();
if (readMethod != null) {
ResolvableType sourceResolvableType = ResolvableType.forMethodReturnType(readMethod);
ResolvableType targetResolvableType = ResolvableType.forMethodParameter(writeMethod, 0);
boolean isAssignable = !sourceResolvableType.hasUnresolvableGenerics() && !targetResolvableType.hasUnresolvableGenerics() ? targetResolvableType.isAssignableFrom(sourceResolvableType) : ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType());
if (isAssignable) {
try {
if (!Modifier.isPublic(readMethod.getDeclaringClass().getModifiers())) {
readMethod.setAccessible(true);
}
Object value = readMethod.invoke(source);
if (!Modifier.isPublic(writeMethod.getDeclaringClass().getModifiers())) {
writeMethod.setAccessible(true);
}
writeMethod.invoke(target, value);
} catch (Throwable var18) {
throw new FatalBeanException("Could not copy property '" + targetPd.getName() + "' from source to target", var18);
}
}
}
}
}
}
}4.beanUtils的簡單示例
public class BeanToolUtils {
public static void copy(Object source, Object target) throws Exception {
Class<?> sourceClass = source.getClass();
Class<?> targeteClass = target.getClass();
Field[] fields = targeteClass.getDeclaredFields();
// 輸出字段信息
for (Field field : fields) {
String name = field.getName();
if ("serialVersionUID".equals(name)) {
continue;
}
String getterName = "get" + name.substring(0, 1).toUpperCase() + name.substring(1);
String setterName = "set" + name.substring(0, 1).toUpperCase() + name.substring(1);
Method getMethod = sourceClass.getMethod(getterName);
if(!ObjectUtils.isEmpty(getMethod)){
Object val = getMethod.invoke(source);
Method setMethod = targeteClass.getMethod(setterName,field.getType());
setMethod.invoke(target, val);
}
}
}
}說明:
獲取目標bean的class對象,通過class對象獲取目標bean的所有屬性,循環(huán)屬性信息,獲取屬性的get和set方法,執(zhí)行來源bean的get方法獲取屬性值,執(zhí)行目標bean的set方法,設置屬性值,完成bean的賦值操作。
總結
以上為個人經驗,希望能給大家一個參考,也希望大家多多支持腳本之家。
相關文章
解決MyEclipse10.7部署報錯拋空指針異常問題的方法
這篇文章主要介紹了解決MyEclipse10.7部署報錯拋空指針異常問題的方法,需要的朋友可以參考下2015-12-12
解決javaBean規(guī)范導致json傳參首字母大寫將永遠獲取不到問題
這篇文章主要介紹了解決javaBean規(guī)范導致json傳參首字母大寫將永遠獲取不到問題,具有很好的參考價值,希望對大家有所幫助。如有錯誤或未考慮完全的地方,望不吝賜教2021-07-07
Spring JDK動態(tài)代理實現(xiàn)過程詳解
這篇文章主要介紹了Spring JDK動態(tài)代理實現(xiàn)過程詳解,文中通過示例代碼介紹的非常詳細,對大家的學習或者工作具有一定的參考學習價值,需要的朋友可以參考下2020-02-02

