日韩性视频-久久久蜜桃-www中文字幕-在线中文字幕av-亚洲欧美一区二区三区四区-撸久久-香蕉视频一区-久久无码精品丰满人妻-国产高潮av-激情福利社-日韩av网址大全-国产精品久久999-日本五十路在线-性欧美在线-久久99精品波多结衣一区-男女午夜免费视频-黑人极品ⅴideos精品欧美棵-人人妻人人澡人人爽精品欧美一区-日韩一区在线看-欧美a级在线免费观看

歡迎訪問(wèn) 生活随笔!

生活随笔

當(dāng)前位置: 首頁(yè) > 编程语言 > java >内容正文

java

java 对象复制字段_利用Java反射机制实现对象相同字段的复制

發(fā)布時(shí)間:2025/3/8 java 23 豆豆
生活随笔 收集整理的這篇文章主要介紹了 java 对象复制字段_利用Java反射机制实现对象相同字段的复制 小編覺(jué)得挺不錯(cuò)的,現(xiàn)在分享給大家,幫大家做個(gè)參考.

一。如何實(shí)現(xiàn)不同類型對(duì)象之間的復(fù)制問(wèn)題?

1、為什么會(huì)有這個(gè)問(wèn)題?

近來(lái)在進(jìn)行一個(gè)項(xiàng)目開發(fā)的時(shí)候,為了隱藏后端數(shù)據(jù)庫(kù)表結(jié)構(gòu)、同時(shí)也為了配合給前端一個(gè)更友好的API接口文檔(swagger API文檔),我采用POJO來(lái)對(duì)應(yīng)數(shù)據(jù)表結(jié)構(gòu),使用VO來(lái)給傳遞前端要展示的數(shù)據(jù),同時(shí)使用DTO來(lái)進(jìn)行請(qǐng)求參數(shù)的封裝。以上是一個(gè)具體的場(chǎng)景,可以發(fā)現(xiàn)這樣子一個(gè)現(xiàn)象:POJO、VO、DTO對(duì)象是同一個(gè)數(shù)據(jù)的不同視圖,所以會(huì)有很多相同的字段,由于不同的地方使用不同的對(duì)象,無(wú)可避免的會(huì)存在對(duì)象之間的值遷移問(wèn)題,遷移的一個(gè)特征就是需要遷移的值字段相同。字段相同,于是才有了不同對(duì)象之間進(jìn)行值遷移復(fù)制的問(wèn)題。

2、現(xiàn)有的解決方法

一個(gè)一個(gè)的get出來(lái)后又set進(jìn)去。這個(gè)方法無(wú)可避免會(huì)增加很多的編碼復(fù)雜度,還是一些很沒(méi)有營(yíng)養(yǎng)的代碼,看多了還會(huì)煩,所以作為一個(gè)有點(diǎn)小追求的程序員都沒(méi)有辦法忍受這種摧殘。

使用別人已經(jīng)存在的工具。在spring包里面有一個(gè)可以復(fù)制對(duì)象屬性的工具方法,可以進(jìn)行對(duì)象值的復(fù)制,下一段我們?cè)敿?xì)去分析它的這個(gè)工具方法。

自己動(dòng)手豐衣足食。自己造工具來(lái)用,之所以自己造工具不是因?yàn)橄矚g造工具,而是現(xiàn)有的工具沒(méi)辦法解決自己的需求,不得已而為之。

二、他山之石可以攻玉,詳談spring的對(duì)象復(fù)制工具

1、看看spring的對(duì)象復(fù)制工具到底咋樣?

類名:org.springframework.beans.BeanUtils

這個(gè)類里面所有的屬性復(fù)制的方法都調(diào)用了同一個(gè)方法,我們就直接分析這個(gè)原始的方法就行了。

/**

* Copy the property values of the given source bean into the given target bean.

*

Note: The source and target classes do not have to match or even be derived

* from each other, as long as the properties match. Any bean properties that the

* source bean exposes but the target bean does not will silently be ignored.

* @param source the source bean:也就是說(shuō)要從這個(gè)對(duì)象里面復(fù)制值出去

* @param target the target bean:出去就是復(fù)制到這里面來(lái)

* @param editable the class (or interface) to restrict property setting to:這個(gè)類對(duì)象是target的父類或其實(shí)現(xiàn)的接口,用于控制屬性復(fù)制的范圍

* @param ignoreProperties array of property names to ignore:需要忽略的字段

* @throws BeansException if the copying failed

* @see BeanWrapper

*/

private static void copyProperties(Object source, Object target, Class> editable, String... ignoreProperties)

throws BeansException {

//這里在校驗(yàn)要復(fù)制的對(duì)象是不可以為null的,這兩個(gè)方法可是會(huì)報(bào)錯(cuò)的!!

Assert.notNull(source, "Source must not be null");

Assert.notNull(target, "Target must not be null");

//這里和下面的代碼就有意思了

Class> actualEditable = target.getClass();//獲取目標(biāo)對(duì)象的動(dòng)態(tài)類型

//下面判斷的意圖在于控制屬性復(fù)制的范圍

if (editable != null) {

//必須是target對(duì)象的父類或者其實(shí)現(xiàn)的接口類型,相當(dāng)于instanceof運(yùn)算符

if (!editable.isInstance(target)) {

throw new IllegalArgumentException("Target class [" + target.getClass().getName() +

"] not assignable to Editable class [" + editable.getName() + "]");

}

actualEditable = editable;

}

//不得不說(shuō),下面這段代碼乖巧的像綿羊,待我們來(lái)分析分析它是如何如何乖巧的

PropertyDescriptor[] targetPds = getPropertyDescriptors(actualEditable);//獲取屬性描述,描述是什么?描述就是對(duì)屬性的方法信息的封裝,好乖。

List ignoreList = (ignoreProperties != null ? Arrays.asList(ignoreProperties) : null);

//重頭戲開始了!開始進(jìn)行復(fù)制了

for (PropertyDescriptor targetPd : targetPds) {

//先判斷有沒(méi)有寫方法,沒(méi)有寫方法我也就沒(méi)有必要讀屬性出來(lái)了,這個(gè)懶偷的真好!

Method writeMethod = targetPd.getWriteMethod();

//首先,沒(méi)有寫方法的字段我不寫,乖巧撒?就是說(shuō)你不讓我改我就不改,讓我忽略我就忽略!

if (writeMethod != null && (ignoreList == null || !ignoreList.contains(targetPd.getName()))) {

PropertyDescriptor sourcePd = getPropertyDescriptor(source.getClass(), targetPd.getName());

//如果沒(méi)辦法從原對(duì)象里面讀出屬性也沒(méi)有必要繼續(xù)了

if (sourcePd != null) {

Method readMethod = sourcePd.getReadMethod();

//這里就更乖巧了!寫方法不讓我寫我也不寫!!!

if (readMethod != null &&

ClassUtils.isAssignable(writeMethod.getParameterTypes()[0], readMethod.getReturnType())) {

try {

//這里就算了,來(lái)都來(lái)了,就乖乖地進(jìn)行值復(fù)制吧,別搞東搞西的了

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 ex) {

throw new FatalBeanException(

"Could not copy property '" + targetPd.getName() + "' from source to target", ex);

}

}

}

}

}

}

2、對(duì)復(fù)制工具的一些看法和總結(jié)

總結(jié)上一段代碼的分析,我們發(fā)現(xiàn)spring自帶的工具有以下特點(diǎn):

它名副其實(shí)的是在復(fù)制屬性,而不是字段!!

它可以通過(guò)一個(gè)目標(biāo)對(duì)象的父類或者其實(shí)現(xiàn)的接口來(lái)控制需要復(fù)制屬性的范圍

很貼心的可以忽略原對(duì)象的某些字段,可以通過(guò)2的方法忽略某些目標(biāo)對(duì)象的字段

但是,這遠(yuǎn)遠(yuǎn)不夠!!!我需要如下的功能:

復(fù)制對(duì)象的字段,而不是屬性,也就是說(shuō)我需要一個(gè)更暴力的復(fù)制工具。

我需要忽略原對(duì)象的某些字段,同時(shí)也能夠忽略目標(biāo)對(duì)象的某些字段。

我的項(xiàng)目還需要忽略原對(duì)象為null的字段和目標(biāo)對(duì)象不為null的字段

帶著這三個(gè)需求,開始我的工具制造。

總結(jié)

以上是生活随笔為你收集整理的java 对象复制字段_利用Java反射机制实现对象相同字段的复制的全部?jī)?nèi)容,希望文章能夠幫你解決所遇到的問(wèn)題。

如果覺(jué)得生活随笔網(wǎng)站內(nèi)容還不錯(cuò),歡迎將生活随笔推薦給好友。