最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

java反射調(diào)用get/set方法實(shí)現(xiàn)

 更新時(shí)間:2025年12月23日 09:31:25   作者:吳名氏.  
本文文章介紹了在Java中使用反射調(diào)用get/set方法時(shí),如何通過(guò)Introspector和PropertyDescriptor來(lái)更優(yōu)雅地處理,下面就來(lái)詳細(xì)的介紹一下,感興趣的可以了解一下

1 前言

最新工作中,遇到了通過(guò)反射調(diào)用get/set方法的地方,雖然反射的性能不是很好,但是相比較于硬編碼的不易擴(kuò)展,getDeclareFields可以拿到所有的成員變量,后續(xù)添加或刪除成員變量時(shí),不用修改代碼,且應(yīng)用次數(shù)只在修改數(shù)據(jù)時(shí)使用,故犧牲一些性能提高擴(kuò)展性

2 傳統(tǒng)的方式

見(jiàn)過(guò)很多人通過(guò)反射調(diào)用get/set方法都是通過(guò)獲取屬性的name,然后通過(guò)字符串截取將首字母大寫(xiě),再拼上get/set來(lái)做

String fieldName = field.getName();
String getMethodName = "get" + fieldName.substring(0, 1).toUpperCase() + fieldName.substring(1);

也可以通過(guò)fieldName轉(zhuǎn)成字符數(shù)組,首個(gè)字符-32來(lái)避免字符串截取的

String fieldName = field.getName();
char[] chars = fieldName.toCharArray();
chars[0] = (char)(chars[0] - 32);
String getMethodName = "get" + new String(chars);

我覺(jué)得兩種方式都可以,但是不知道有沒(méi)有遇到過(guò),生成的get/set方法并不是已get/set開(kāi)頭的,而是以is開(kāi)頭的,比如boolean類(lèi)型的成員變量。這個(gè)時(shí)候我們就需要去判斷屬性的類(lèi)型,然后用不同的前綴來(lái)拼接get/set方法名。其實(shí),在jdk中已經(jīng)包含了這樣的工具類(lèi)

3 Introspector和PropertyDescriptor

關(guān)于這兩個(gè)類(lèi)的詳細(xì)介紹,我這里就不說(shuō)了,簡(jiǎn)單的理解就是對(duì)象信息的描述,里面提供了一些API方便我們拿到對(duì)象的信息

BeanInfo beanInfo;
try {
    beanInfo = Introspector.getBeanInfo(template.getClass());
} catch (IntrospectionException e) {
    log.info("xxxxxxxxxxxxxxxx", e);
    return null;
}

List<PropertyDescriptor> descriptors = Arrays.stream(beanInfo.getPropertyDescriptors()).filter(p -> {
    String name = p.getName();
    //過(guò)濾掉不需要修改的屬性
    return !"class".equals(name) && !"id".equals(name);
}).collect(Collectors.toList());

for (PropertyDescriptor descriptor : descriptors) {
    //descriptor.getWriteMethod()方法對(duì)應(yīng)set方法
    Method readMethod = descriptor.getReadMethod();
    System.out.println(descriptor.getName());
    try {
        Object o = readMethod.invoke(template);
        System.out.println(o);
    } catch (IllegalAccessException | InvocationTargetException e) {
        log.info("xxxxxxxxxxxxxxxx", e);
        return null;
    }
}

PropertyDescriptor類(lèi)提供了getReadMethod和getWriteMethod,其實(shí)就是對(duì)于get/set方法,至于方法名稱(chēng)不需要我們來(lái)關(guān)于,這樣就可以避免方法名拼錯(cuò)的情況了。 另外PropertyDescriptor除了可以通過(guò)Introspector獲取,也可以自己new來(lái)創(chuàng)建,其構(gòu)造方法還是比較全的

通常傳遞一個(gè)屬性的名稱(chēng)和類(lèi)對(duì)象class就可以了

List<Field> fields = Arrays.stream(template.getClass().getDeclaredFields()).filter(f -> {
    String name = f.getName();
    //過(guò)濾掉不需要修改的屬性
    return !"id".equals(name) && !"serialVersionUID".equals(name);
}).collect(Collectors.toList());

for (Field field : fields) {
    try {
        PropertyDescriptor descriptor = new PropertyDescriptor(field.getName(), template.getClass());
        Method readMethod = descriptor.getReadMethod();
        Object o = readMethod.invoke(template);
        System.out.println(o);
    } catch (IntrospectionException | IllegalAccessException | InvocationTargetException e) {
        e.printStackTrace();
    }
}

通過(guò)上面兩種不同的實(shí)現(xiàn)方式可以看到,Introspector會(huì)額外有一個(gè)class屬性,但是類(lèi)似serialVersionUID不會(huì)算在內(nèi);而自定義PropertyDescriptor需要通過(guò)反射拿到所有的屬性,雖然不會(huì)有class屬性,但是serialVersionUID會(huì)算在內(nèi),使用的時(shí)候需要注意一下。 如果你以為這就是Introspector的全部功能,那就大錯(cuò)特錯(cuò)了。Introspector不同于普通的反射,反射一次,一段時(shí)間內(nèi)可重復(fù)使用,為什么不是永久呢,看下源碼

/**
     * Introspect on a Java Bean and learn about all its properties, exposed
     * methods, and events.
     * <p>
     * If the BeanInfo class for a Java Bean has been previously Introspected
     * then the BeanInfo class is retrieved from the BeanInfo cache.
     *
     * @param beanClass  The bean class to be analyzed.
     * @return  A BeanInfo object describing the target bean.
     * @exception IntrospectionException if an exception occurs during
     *              introspection.
     * @see #flushCaches
     * @see #flushFromCaches
     */
    public static BeanInfo getBeanInfo(Class<?> beanClass)
        throws IntrospectionException
    {
        if (!ReflectUtil.isPackageAccessible(beanClass)) {
            return (new Introspector(beanClass, null, USE_ALL_BEANINFO)).getBeanInfo();
        }
        ThreadGroupContext context = ThreadGroupContext.getContext();
        BeanInfo beanInfo;
        synchronized (declaredMethodCache) {
            beanInfo = context.getBeanInfo(beanClass);
        }
        if (beanInfo == null) {
            beanInfo = new Introspector(beanClass, null, USE_ALL_BEANINFO).getBeanInfo();
            synchronized (declaredMethodCache) {
                context.putBeanInfo(beanClass, beanInfo);
            }
        }
        return beanInfo;
    }

注意中間加粗標(biāo)紅的代碼,這里除了同步之外,還做了一個(gè)本地的緩存

BeanInfo getBeanInfo(Class<?> type) {
    return (this.beanInfoCache != null)
            ? this.beanInfoCache.get(type)
            : null;
}

這個(gè)beanInfoCache 其實(shí)是一個(gè)WeakHashMap,每次gc被回收,所以上面說(shuō)一段時(shí)間內(nèi)可以重復(fù)使用而不是永久,也是為了避免OOM吧

到此這篇關(guān)于java反射調(diào)用get/set方法實(shí)現(xiàn)的文章就介紹到這了,更多相關(guān)java反射調(diào)用get/set內(nèi)容請(qǐng)搜索腳本之家以前的文章或繼續(xù)瀏覽下面的相關(guān)文章希望大家以后多多支持腳本之家!

相關(guān)文章

最新評(píng)論

静乐县| 石门县| 龙门县| 靖西县| 德保县| 灌南县| 朝阳县| 香河县| 县级市| 龙口市| 邹平县| 宝鸡市| 延长县| 盘山县| 巴彦淖尔市| 民和| 琼中| 卢湾区| 兴安盟| 瓦房店市| 浙江省| 仁怀市| 湄潭县| 昌邑市| 开远市| 喜德县| 五华县| 奎屯市| 灵丘县| 龙岩市| 方正县| 龙川县| 七台河市| 萨迦县| 蓬莱市| 沧州市| 慈溪市| 张掖市| 乐业县| 山西省| 大丰市|