成人国产在线小视频_日韩寡妇人妻调教在线播放_色成人www永久在线观看_2018国产精品久久_亚洲欧美高清在线30p_亚洲少妇综合一区_黄色在线播放国产_亚洲另类技巧小说校园_国产主播xx日韩_a级毛片在线免费

資訊專欄INFORMATION COLUMN

封裝BeanMap以及java的反射和內(nèi)省

張巨偉 / 3592人閱讀

摘要:所以,我實(shí)現(xiàn)了一個(gè)稱為的類來應(yīng)用反射?,F(xiàn)在流行的語言大都支持反射。這組內(nèi)省主要是針對(duì)類進(jìn)行操作的,能夠獲取類的屬性信息??梢钥吹?,通過的內(nèi)省機(jī)制,解決了的最關(guān)鍵的問題。在封裝反射的時(shí)候,會(huì)充分考慮到各種情況。

BeanMap

學(xué)習(xí)具體的技術(shù)工具的好辦法就是些Demo、造輪子。所以,我實(shí)現(xiàn)了一個(gè)稱為BeanMap的類來應(yīng)用java反射API。

這個(gè)BeanMap的功能是將一個(gè)Bean包裝成Map來使用。對(duì)調(diào)用者來說,是以操作Map的方式來操作BeanMap,
但是,實(shí)際上的數(shù)據(jù)是存儲(chǔ)在被包裝的Bean對(duì)象中的。

這種思路類似適配器模式,可以讓你以Map的接口操作Bean對(duì)象。
但又有點(diǎn)像“視圖”思想,真正的數(shù)據(jù)是存儲(chǔ)在Bean對(duì)象中的,BeanMap只是對(duì)它進(jìn)行操作的“視圖”。對(duì)BeanMap的所有操作都會(huì)反映在后面的Bean對(duì)象中。

下面是BeanMap的一個(gè)使用例子。

    @Getter
    @Setter
    class Point {
        private Integer x = 2;
        private Integer y = 1;
    }
BeanMap map = new BeanMap(new Point());
map.put("x", 10);
map.get("y");

示例中的Point這個(gè)Bean類擁有屬性x和y。但是被BeanMap包裝后,它就變成了一個(gè)擁有鍵"x"和鍵"y"的Map了。

那這個(gè)BeanMap類有什么實(shí)際應(yīng)用呢?哈哈這只是我為了寫反射的DEMO自己設(shè)計(jì)出來的一個(gè)類。

java反射

稍微思考下不難發(fā)現(xiàn),BeanMap實(shí)現(xiàn)的關(guān)鍵點(diǎn)在于,
BeanMap接受外部傳入的鍵,這是一個(gè)字符串。之后,它得到找到Bean對(duì)象中對(duì)應(yīng)的getter和setter,并操作Bean對(duì)象。

將這個(gè)要求向通用化的方向分析,也即提供一個(gè)與函數(shù)匹配的字符串,得到對(duì)該函數(shù)的引用。

通過反射,就能夠?qū)崿F(xiàn)上面的要求。
現(xiàn)在流行的語言大都支持反射。反射能夠在運(yùn)行時(shí)得到程序元數(shù)據(jù),比如某類的信息。
還能夠根據(jù)這些元信息來修改程序狀態(tài)或邏輯。
由于反射是在 運(yùn)行 時(shí)得到的信息,那么支持反射的語言也必然要在程序運(yùn)行時(shí)將這些元信息存放在內(nèi)存某處。

java語言提供了反射API,這里是官方完整的文檔:https://docs.oracle.com/javas... 。
對(duì)于反射出來的信息,Java的反射API將其以類的形式包裝提供。
Java的反射機(jī)制提供了4個(gè)類:

Class 類

Constructor 構(gòu)造器

Field 屬性

Method 方法

現(xiàn)在,試圖利用反射API,得到一個(gè)POJO類的所有屬性名稱。如下:

    private List names() {
        Method[] methods = bean.getClass().getMethods();
        List result = new ArrayList<>();
        for (Method getter : methods) {
            int mod = getter.getModifiers();
            if (getter.getName().startsWith("get") && !Modifier.isPublic(mod)) {
                String name = getter.getName().substring("key".length());
                name = name.substring(0, 1).toLowerCase() + key.substring(1);
                result.add(name);
            }
        }
        return result;
    }

上述代碼的思路很簡單,java提供的反射API,能夠得到該類的所有方法列表。按照約定,POJO類的屬性xxx的getter方法都命名為GetXxx。那么,遍歷這個(gè)表,找出所有g(shù)etter,字符串處理下,就得到了所有的屬性。

通過調(diào)用對(duì)象的getClass()方法得到一個(gè)Class對(duì)象,也即反射出該對(duì)象的Class信息。Class::getMethods函數(shù)則是反射出該類的所有方法。

Method::getModifiers得到方法的修飾符信息。它是一個(gè)整數(shù),我猜測(cè)是用位標(biāo)記各個(gè)修飾符的,處理它需要用到位運(yùn)算。不過可以使用Modifier這個(gè)類的工具方法去處理它。

不過,這里是想實(shí)現(xiàn)BeanMap。一種思路是,通過對(duì)反射出的列表進(jìn)行一次處理,除了得到每個(gè)屬性的名稱外,還要得到它們的getter和setter。下面是一種粗暴的實(shí)現(xiàn):

    private List fileds() {
        Method[] fields = bean.getClass().getMethods();
        List result = new ArrayList<>();
        for (Method getter : fields) {
            if (getter.getName().startsWith("get") && isVaildModifier(getter.getModifiers())) {
                String setterName = "set" + getter.getName().substring("get".length());
                for (Method setter : fields) {
                    if (setter.getName().equals(setterName) && isVaildModifier(setter.getModifiers())) {
                        result.add(new Item(this.bean, getter, setter));
                    }
                }
            }
        }
        return result;
    }

當(dāng)然,上面的實(shí)現(xiàn)思路缺點(diǎn)很多。
首先,是性能問題。上面的代碼雖然能實(shí)現(xiàn)功能,但是太暴力了。
雖然一個(gè)POJO類的方法頂多幾十個(gè),但是考慮到在具體的實(shí)踐中,這些都是作為較為底層的基礎(chǔ)設(shè)施,項(xiàng)目中可能會(huì)頻繁被業(yè)務(wù)代碼調(diào)用,因此對(duì)其進(jìn)行性能上的分析是有必要的。

其次,上面這段邏輯考慮的也不全面。上面的邏輯是對(duì)公開的getter進(jìn)行進(jìn)一步的處理的,那么,如果getter是static的呢?
如果getter被native修飾呢?如果是超類所擁有的屬性,那么該如何處理這種情況呢?

java內(nèi)省API

為了方便使用,java針對(duì)反射API進(jìn)行了封裝,提供了一組內(nèi)省API。
這組內(nèi)省API主要是針對(duì)POJO類進(jìn)行操作的,能夠獲取POJO類的屬性信息。

那么,有了jdk自帶的用于對(duì)Bean進(jìn)行反射的工具后,上面的邏輯既可以簡化了:

    private List fileds() throws IntrospectionException {
        BeanInfo beanInfo = Introspector.getBeanInfo(List.class);
        return Stream.of(beanInfo.getPropertyDescriptors()).map((pd) -> {
            return new Item(this.bean, pd.getReadMethod(), pd.getWriteMethod());
        }).collect(Collectors.toList());
    }

使用getBeanInfo方法獲取某個(gè)Bean類的內(nèi)省信息,這些信息封裝在BeanInfo對(duì)象中。

PropertyDescriptor是對(duì)Bean類中的一個(gè)屬性的封裝,通過它可以獲取該屬性的名稱、getter方法、setter方法等信息。

beanInfo::getPropertyDescriptors獲取Bean類的所有的PropertyDescriptor

可以看到,通過java的內(nèi)省機(jī)制,解決了BeanMap的最關(guān)鍵的問題。而且,使用java自帶的內(nèi)省機(jī)制比自己通過反射API處理有以下好處:

內(nèi)省API基于反射API進(jìn)行的封裝,使用更高層次的接口,當(dāng)然更省心,開發(fā)效率更高。

jdk在封裝反射API的時(shí)候,會(huì)充分考慮到各種情況。如考慮到繼承這一問題,Introspector::getBeanInfo函數(shù)可接收第二個(gè)參數(shù),只反射出繼承鏈中該類到第二個(gè)參數(shù)指定類之間類的屬性。

內(nèi)省API也充分考慮到了性能,其中擁有緩存機(jī)制,以提升性能。

最后

解決了最關(guān)鍵的邏輯后,剩下的部分,就是對(duì)Map接口進(jìn)行實(shí)現(xiàn),填充一些封裝目的的代碼。在這里,我將核心的邏輯放在BeanMapImpl類中,而BeanMap僅僅負(fù)責(zé)實(shí)現(xiàn)Map接口,相關(guān)操作轉(zhuǎn)發(fā)到BeanMapImpl相應(yīng)的方法中實(shí)現(xiàn)。這樣顯得程序結(jié)構(gòu)更為清晰:
https://github.com/frapples/j...

文章版權(quán)歸作者所有,未經(jīng)允許請(qǐng)勿轉(zhuǎn)載,若此文章存在違規(guī)行為,您可以聯(lián)系管理員刪除。

轉(zhuǎn)載請(qǐng)注明本文地址:http://systransis.cn/yun/71449.html

相關(guān)文章

  • Reflection:Java反射機(jī)制應(yīng)用場景

    近期在維護(hù)公司項(xiàng)目的時(shí)候遇到一個(gè)問題,因?yàn)閷?shí)體類中的 set 方法涉及到了業(yè)務(wù)邏輯,因此在給對(duì)象賦值的過程中不能夠使用 set 方法,為了實(shí)現(xiàn)功能,所以采用了反射的機(jī)制給對(duì)象屬性賦值,借此機(jī)會(huì)也了解了反射的一些具體用法和使用場景,分以下兩點(diǎn)對(duì)反射進(jìn)行分析: 反射的優(yōu)勢(shì)和劣勢(shì) 反射的應(yīng)用場景 反射的優(yōu)勢(shì)和劣勢(shì) ??個(gè)人理解,反射機(jī)制實(shí)際上就是上帝模式,如果說方法的調(diào)用是 Java 正確的打開方式...

    浠ラ箍 評(píng)論0 收藏0
  • 詳敘BeanWrapperPropertyDescriptor

    摘要:關(guān)于它的數(shù)據(jù)轉(zhuǎn)換使用了如下兩種機(jī)制隸屬于規(guī)范。這種類中的方法主要用于訪問私有的字段,且方法名符合某種命名規(guī)則。如果在兩個(gè)模塊之間傳遞信息,可以將信息封裝進(jìn)中,這種對(duì)象稱為值對(duì)象,或。 每篇一句 千古以來要飯的沒有要早飯的,知道為什么嗎? 相關(guān)閱讀 【小家Spring】聊聊Spring中的數(shù)據(jù)轉(zhuǎn)換:Converter、ConversionService、TypeConverter、Pro...

    APICloud 評(píng)論0 收藏0
  • 徒手?jǐn)]框架--實(shí)現(xiàn)IoC

    摘要:從而能夠進(jìn)一步深入了解框架。至此我們框架開發(fā)完成。雖然說閱讀源碼是了解框架的最終手段。但是框架作為一個(gè)生產(chǎn)框架,為了保證通用和穩(wěn)定,源碼必定是高度抽象,且處理大量細(xì)節(jié)。下一篇文章應(yīng)該會(huì)是徒手?jǐn)]框架實(shí)現(xiàn)。 原文地址:https://www.xilidou.com/2018/... Spring 作為 J2ee 開發(fā)事實(shí)上的標(biāo)準(zhǔn),是每個(gè)Java開發(fā)人員都需要了解的框架。但是Spring 的...

    rottengeek 評(píng)論0 收藏0
  • 【小家Spring】Spring IoC是如何使用BeanWrapperJava內(nèi)省結(jié)合起來給Be

    摘要:從層層委托的依賴關(guān)系可以看出,的依賴注入給屬性賦值是層層委托的最終給了內(nèi)省機(jī)制,這是框架設(shè)計(jì)精妙處之一。當(dāng)然分享到你的朋友圈讓更多小伙伴看到也是被作者本人許可的若對(duì)技術(shù)內(nèi)容感興趣可以加入群交流高工架構(gòu)師群。 每篇一句 具備了技術(shù)深度,遇到問題可以快速定位并從根本上解決。有了技術(shù)深度之后,學(xué)習(xí)其它技術(shù)可以更快,再深入其它技術(shù)也就不會(huì)害怕 相關(guān)閱讀 【小家Spring】聊聊Spring中的...

    waruqi 評(píng)論0 收藏0

發(fā)表評(píng)論

0條評(píng)論

最新活動(dòng)
閱讀需要支付1元查看
<