java反射機(jī)制及beanUtils的實(shí)現(xiàn)原理分析
1.反射機(jī)制說(shuō)明
Java的反射機(jī)制允許程序在運(yùn)行時(shí)檢查和操作類、方法、字段等結(jié)構(gòu)。通過(guò)反射,可以動(dòng)態(tài)地創(chuàng)建對(duì)象、調(diào)用方法、獲取/設(shè)置字段的值,而無(wú)需在編譯時(shí)確定這些操作。
反射的核心類是java.lang.reflect
包中的Method
、Field
和Constructor
等。使用反射需要注意性能開銷和安全性問題。
- 獲取類的Class對(duì)象
Class<?> clazz = MyClass.class;
- 實(shí)例化對(duì)象
MyClass myObject = (MyClass) clazz.getDeclaredConstructor().newInstance();
- 獲取和調(diào)用方法
Method method = clazz.getDeclaredMethod("methodName", parameterTypes); method.setAccessible(true); // 如果方法是private的,需要設(shè)置accessible為true Object result = method.invoke(myObject, args);
- 獲取和設(shè)置字段值
Field field = clazz.getDeclaredField("fieldName"); field.setAccessible(true); // 如果字段是private的,需要設(shè)置accessible為true Object value = field.get(myObject); field.set(myObject, newValue);
- 操作構(gòu)造函數(shù)
Constructor<?> constructor = clazz.getDeclaredConstructor(parameterTypes); constructor.setAccessible(true); // 如果構(gòu)造函數(shù)是private的,需要設(shè)置accessible為true MyClass myObject = (MyClass) constructor.newInstance(args);
2.VO,DTO,PO的說(shuō)明
VO(Value Object)值對(duì)象
VO就是展示用的數(shù)據(jù),不管展示方式是網(wǎng)頁(yè),還是客戶端,還是APP,只要是這個(gè)東西是讓人看到的,這就叫VO,這個(gè)大家都很理解,反正就是我們的接口返回給前端的對(duì)象都是用VO來(lái)返回,跟DTO不一樣的是,VO是我們返回給前端,DTO是我們從前端接收的時(shí)候用的,即一個(gè)是入?yún)?,一個(gè)是返回結(jié)果
DTO(Data Transfer Object)數(shù)據(jù)傳輸對(duì)象
這個(gè)傳輸通常指的前后端之間的傳輸
DTO是一個(gè)比較特殊的對(duì)象,他有兩種存在形式:
- 一種是前端和后端交互所使用的對(duì)象
- 另一種是微服務(wù)之間的一種傳輸對(duì)象,我們一般也是用DTO來(lái)進(jìn)行傳輸
PO(Persistant Object)持久對(duì)象
PO比較好理解,簡(jiǎn)單說(shuō)PO就是數(shù)據(jù)庫(kù)中的記錄,一個(gè)PO的數(shù)據(jù)結(jié)構(gòu)對(duì)應(yīng)著庫(kù)中表的結(jié)構(gòu),表中的一條記錄就是一個(gè)PO對(duì)象,通常PO里面除了get,set之外沒有別的方法,對(duì)于PO來(lái)說(shuō),數(shù)量是相對(duì)固定的,一定不會(huì)超過(guò)數(shù)據(jù)庫(kù)表的數(shù)量,等同于BO,這倆概念是一致的
3.beanUtils的實(shí)現(xiàn)原理
在后端的各個(gè)層中進(jìn)行數(shù)據(jù)傳輸時(shí),經(jīng)常使用beanUtils進(jìn)行bean的拷貝,其實(shí)現(xiàn)原理就是通過(guò)java的放射機(jī)制實(shí)現(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的簡(jiǎn)單示例
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); } } } }
說(shuō)明:
獲取目標(biāo)bean的class對(duì)象,通過(guò)class對(duì)象獲取目標(biāo)bean的所有屬性,循環(huán)屬性信息,獲取屬性的get和set方法,執(zhí)行來(lái)源bean的get方法獲取屬性值,執(zhí)行目標(biāo)bean的set方法,設(shè)置屬性值,完成bean的賦值操作。
總結(jié)
以上為個(gè)人經(jīng)驗(yàn),希望能給大家一個(gè)參考,也希望大家多多支持腳本之家。
相關(guān)文章
java中靜態(tài)導(dǎo)入機(jī)制用法實(shí)例詳解
這篇文章主要介紹了java中靜態(tài)導(dǎo)入機(jī)制用法實(shí)例詳解的相關(guān)資料,需要的朋友可以參考下2017-07-07java幾種排序算法的實(shí)現(xiàn)及簡(jiǎn)單分析
這篇文章主要介紹了java幾種排序算法的實(shí)現(xiàn)及簡(jiǎn)單分析,實(shí)例分析了插入排序、希爾排序、選擇排序等常用排序算法,并分析了各個(gè)算法的優(yōu)劣,需要的朋友可以參考下2015-05-05解決MyEclipse10.7部署報(bào)錯(cuò)拋空指針異常問題的方法
這篇文章主要介紹了解決MyEclipse10.7部署報(bào)錯(cuò)拋空指針異常問題的方法,需要的朋友可以參考下2015-12-12解決javaBean規(guī)范導(dǎo)致json傳參首字母大寫將永遠(yuǎn)獲取不到問題
這篇文章主要介紹了解決javaBean規(guī)范導(dǎo)致json傳參首字母大寫將永遠(yuǎn)獲取不到問題,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-07-07Spring JDK動(dòng)態(tài)代理實(shí)現(xiàn)過(guò)程詳解
這篇文章主要介紹了Spring JDK動(dòng)態(tài)代理實(shí)現(xiàn)過(guò)程詳解,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-02-02Java fastdfs客戶端實(shí)現(xiàn)上傳下載文件
這篇文章主要介紹了Java fastdfs客戶端實(shí)現(xiàn)上傳下載文件,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下2020-10-10