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

java的反射用不好試試內(nèi)省?

 更新時(shí)間:2021年07月19日 08:49:43   作者:二當(dāng)家的白帽子  
使用內(nèi)省相對于直接使用反射更加安全可靠,Java的反射機(jī)制比較特殊,它不同于一般的編程方式,稍不小心就容易破壞類的封裝性。練的不好,就容易走火入魔。沒關(guān)系,很多時(shí)候我們還可以使用Java的內(nèi)省機(jī)制哦

Java的內(nèi)省機(jī)制是什么?

內(nèi)?。↖ntrospection )在心理學(xué)中,它是心理學(xué)基本研究方法之一。內(nèi)省法又稱自我觀察法。它是發(fā)生在內(nèi)部的,我們自己能夠意識到的主觀現(xiàn)象。也可以說是對于自己的主觀經(jīng)驗(yàn)及其變化的觀察。正因?yàn)樗闹饔^性,內(nèi)省法自古以來就成為心理學(xué)界長期的爭論。爭論于它是否客觀,是否可靠。另外內(nèi)省也可看作自我反省,也是儒家強(qiáng)調(diào)的自我思考。從這個(gè)角度說它可以應(yīng)用于計(jì)算機(jī)領(lǐng)域,例如Java內(nèi)省機(jī)制和cocoa內(nèi)省機(jī)制。

Java語言內(nèi)?。↖ntrospector)是Java語言對Bean類屬性、事件的一種缺省處理方法。例如類A中有屬性name,那我們可以通過getName,setName來得到其值或者設(shè)置新的值。通過getName/setName來訪問name屬性,這就是默認(rèn)的規(guī)則。Java中提供了一套API用來訪問某個(gè)屬性的getter/setter方法,通過這些API可以使你不需要了解這個(gè)規(guī)則(但你最好還是要搞清楚),這些API存放于包java.beans中。一般的做法是通過類Introspector來獲取某個(gè)對象的BeanInfo信息,然后通過BeanInfo來獲取屬性的描述器(PropertyDescriptor),通過這個(gè)屬性描述器就可以獲取某個(gè)屬性對應(yīng)的getter/setter方法,然后我們就可以通過反射機(jī)制來調(diào)用這些方法。

以上就是百科的解釋。Java的內(nèi)省最終是用Java的反射實(shí)現(xiàn)的。那為什么不直接用反射,要使用內(nèi)省呢?

使用內(nèi)省替代直接使用反射可以防止破壞類的封裝

我們定義一個(gè)人的類型,其中包括年齡和是否成年兩個(gè)屬性。在修改年齡屬性的時(shí)候會(huì)同時(shí)修改是否成年的屬性。我們假設(shè)18歲和18歲以上就是成年,否則就是未成年。

import java.beans.IntrospectionException;
import java.beans.PropertyDescriptor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.text.MessageFormat;
class Person {
    /**
     * 18歲成年
     */
    private static final int ADULT_AGE = 18;
    /**
     * 年齡
     */
    private int     age;
    /**
     * 是否成年
     */
    private boolean adult;
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
        this.adult = age >= ADULT_AGE;
    }
    public boolean isAdult() {
        return adult;
    }
    public String toString() {
        return MessageFormat.format("age:{0},adult:{1}", age, adult);
    }
}
/**
 * @author 二當(dāng)家的白帽子 https://le-yi.blog.csdn.net/
 */
public class Test {
    /**
     * 利用反射修改對象屬性
     * @param o
     * @param fieldName
     * @param value
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static void changeObjectFieldByReflection(Object o, String fieldName, Object value) throws NoSuchFieldException, IllegalAccessException {
        Field field = o.getClass().getDeclaredField(fieldName);
        field.setAccessible(true);
        field.set(o, value);
    }
    /**
     * 利用內(nèi)省修改對象屬性
     * @param o
     * @param fieldName
     * @param value
     * @throws NoSuchFieldException
     * @throws IllegalAccessException
     */
    public static void changeObjectFieldByIntrospector(Object o, String fieldName, Object value) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        PropertyDescriptor pd = new PropertyDescriptor(fieldName, o.getClass());
        pd.getWriteMethod().invoke(o, value);
    }
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IntrospectionException, InvocationTargetException {
        Person p = new Person();
        changeObjectFieldByReflection(p, "age", 20);
        System.out.println("反射修改屬性破壞類的封裝,使其內(nèi)部狀態(tài)錯(cuò)誤:");
        System.out.println(p);
        changeObjectFieldByIntrospector(p, "age", 18);
        System.out.println("內(nèi)省修改屬性未破壞類的封裝:");
        System.out.println(p);
    }
}

在這里插入圖片描述

可以看到,反射由于是直接修改屬性,所以破壞了類中封裝的邏輯(20歲卻不是成年)。

而內(nèi)省由于修改屬性還是調(diào)用了set方法,也就是說和正常修改對象屬性調(diào)用了相同的方法,所以類的封裝性不會(huì)遭到破壞。

當(dāng)然由于內(nèi)省其實(shí)本質(zhì)也是反射,可以說是封裝了反射,所以如果反射用的正確,也是安全的,我們可以根據(jù)屬性名去獲取相應(yīng)的set和get方法,然后再去調(diào)用,但是這種情況下內(nèi)省使用起來就更方便,畢竟沒有必要重復(fù)發(fā)明一個(gè)車輪子,圓形輪子已經(jīng)是很多年很多年智慧的結(jié)晶了。

那么問題來了,既然內(nèi)省就是調(diào)用set和get方法,那我為什么不直接調(diào)用set和get方法,而要使用內(nèi)省呢?

使用內(nèi)省也一樣可以寫出通用的工具

既然內(nèi)省可以動(dòng)態(tài)獲取信息,那就和反射一樣,可以實(shí)現(xiàn)出通用工具或者框架哦。我們這里實(shí)現(xiàn)一個(gè)可以拷貝任意類型兩個(gè)對象的屬性值的工具方法。

import java.beans.BeanInfo;
import java.beans.IntrospectionException;
import java.beans.Introspector;
import java.beans.PropertyDescriptor;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.text.MessageFormat;
class Person {
    /**
     * 18歲成年
     */
    private static final int ADULT_AGE = 18;
    /**
     * 名字
     */
    private final String  name;
    /**
     * 身高
     */
    private       int     height;
    /**
     * 年齡
     */
    private       int     age;
    /**
     * 是否成年
     */
    private       boolean adult;
    public Person(String name) {
        this.name = name;
    }
    public String getName() {
        return name;
    }
    public int getHeight() {
        return height;
    }
    public void setHeight(int height) {
        this.height = height;
    }
    public int getAge() {
        return age;
    }
    public void setAge(int age) {
        this.age = age;
        this.adult = age >= ADULT_AGE;
    }
    public boolean isAdult() {
        return adult;
    }
    public String toString() {
        return MessageFormat.format("name:{0},height:{1},age:{2},adult:{3}", name, height, age, adult);
    }
}
/**
 * @author 二當(dāng)家的白帽子 https://le-yi.blog.csdn.net/
 */
public class Test {
    /**
     * 將orig的可讀屬性值拷貝到dest的可寫屬性中
     * @param dest
     * @param orig
     * @param <T>
     * @throws IntrospectionException
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     */
    public static <T> void copyProperties(T dest, T orig) throws IntrospectionException, InvocationTargetException, IllegalAccessException {
        BeanInfo beanInfo = Introspector.getBeanInfo(orig.getClass());
        PropertyDescriptor[] pds = beanInfo.getPropertyDescriptors();
        for (PropertyDescriptor pd : pds) {
            Method rm = pd.getReadMethod();
            Method wm = pd.getWriteMethod();
            if (rm != null
                && wm != null) {
                Object value = rm.invoke(orig);
                wm.invoke(dest, value);
            }
        }
    }
    public static void main(String[] args) throws NoSuchFieldException, IllegalAccessException, IntrospectionException, InvocationTargetException {
        Person p2 = new Person("二當(dāng)家的");
        p2.setAge(18);
        p2.setHeight(180);
        System.out.println(p2);
        Person p1 = new Person("大當(dāng)家的");
        System.out.println(p1);
        System.out.println("將二當(dāng)家的可讀屬性值拷貝給大當(dāng)家的可寫屬性:");
        copyProperties(p1, p2);
        System.out.println(p1);
    }
}

在這里插入圖片描述

可以看到,名字沒有被拷貝,其他的屬性值都順利拷貝了。這也是我們期望的結(jié)果。

內(nèi)省很好的保證了類的封裝性,同時(shí)又具有動(dòng)態(tài)獲取對象屬性,和動(dòng)態(tài)修改對象屬性的能力。

總結(jié)

和反射一樣,一般的程序可能也用不到寫內(nèi)省的代碼。但是像apache的beanutils這樣方便的工具,如果沒有反射也沒有內(nèi)省,我真的想不出如何實(shí)現(xiàn)呢。哪怕永遠(yuǎn)不需要用內(nèi)省,了解機(jī)制對我們都有著莫大的好處。

本篇文章就到這里了,希望能給你帶來幫助,也希望您能夠多多關(guān)注腳本之家的更多內(nèi)容!

相關(guān)文章

  • eclipse漢化及jdk安裝環(huán)境配置超詳細(xì)教程(Java安裝教程)

    eclipse漢化及jdk安裝環(huán)境配置超詳細(xì)教程(Java安裝教程)

    這篇文章主要介紹了eclipse漢化及jdk安裝環(huán)境配置超詳細(xì)教程(Java安裝教程),本文通過圖文并茂的形式給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-03-03
  • java環(huán)境變量為什么要配置path和classpath詳細(xì)解答

    java環(huán)境變量為什么要配置path和classpath詳細(xì)解答

    為何配置path?為何配置classpath?當(dāng)時(shí)初學(xué)java時(shí)只是關(guān)心如何做而不去關(guān)心這些問題,接下來介紹一下,感興趣的朋友可以參考下哦
    2013-01-01
  • Spring Boot獲取微信用戶信息的超簡單方法

    Spring Boot獲取微信用戶信息的超簡單方法

    這篇文章主要給大家介紹了關(guān)于Spring Boot獲取微信用戶信息的超簡單方法,文中通過示例代碼介紹的非常詳細(xì),對大家學(xué)習(xí)或者使用Spring Boot具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面來一起學(xué)習(xí)學(xué)習(xí)吧
    2019-09-09
  • Springmvc ResponseBody響應(yīng)json數(shù)據(jù)實(shí)現(xiàn)過程

    Springmvc ResponseBody響應(yīng)json數(shù)據(jù)實(shí)現(xiàn)過程

    這篇文章主要介紹了Springmvc ResponseBody響應(yīng)json數(shù)據(jù)實(shí)現(xiàn)過程,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友可以參考下
    2020-10-10
  • Java+Eclipse+Selenium環(huán)境搭建的方法步驟

    Java+Eclipse+Selenium環(huán)境搭建的方法步驟

    這篇文章主要介紹了Java+Eclipse+Selenium環(huán)境搭建的方法步驟,小編覺得挺不錯(cuò)的,現(xiàn)在分享給大家,也給大家做個(gè)參考。一起跟隨小編過來看看吧
    2019-06-06
  • springboot日志沒有記錄異常問題及解決

    springboot日志沒有記錄異常問題及解決

    在Spring Boot項(xiàng)目中,定時(shí)任務(wù)在服務(wù)器上運(yùn)行時(shí)報(bào)錯(cuò)但未記錄日志,本地運(yùn)行時(shí)控制臺能打印報(bào)錯(cuò)信息,但日志中無記錄,問題出在報(bào)錯(cuò)發(fā)生在線程池中,通過繼承ThreadPoolExecutor并重寫afterExecute方法,可以將異常信息記錄到日志中
    2025-02-02
  • Java SpringBoot使用guava過濾器

    Java SpringBoot使用guava過濾器

    這篇文章主要介紹了Java SpringBoot使用guava過濾器,文章圍繞主題展開詳細(xì)的內(nèi)容戒殺,具有一定的參考價(jià)值,需要的小伙伴可以參考一下
    2022-09-09
  • 責(zé)任鏈模式在spring security過濾器鏈中的應(yīng)用小結(jié)

    責(zé)任鏈模式在spring security過濾器鏈中的應(yīng)用小結(jié)

    責(zé)任鏈模式在SpringSecurity過濾器鏈中的應(yīng)用,通過一系列的過濾器按順序處理請求,每個(gè)過濾器負(fù)責(zé)特定的安全功能,實(shí)現(xiàn)靈活且可擴(kuò)展的請求處理機(jī)制,感興趣的朋友跟隨小編一起看看吧
    2024-11-11
  • springboot整合mybatis-plus實(shí)現(xiàn)多表分頁查詢的示例代碼

    springboot整合mybatis-plus實(shí)現(xiàn)多表分頁查詢的示例代碼

    這篇文章主要介紹了springboot整合mybatis-plus實(shí)現(xiàn)多表分頁查詢的示例代碼,文中通過示例代碼介紹的非常詳細(xì),對大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2021-03-03
  • Map如何根據(jù)key指定條件進(jìn)行過濾篩選

    Map如何根據(jù)key指定條件進(jìn)行過濾篩選

    這篇文章主要介紹了Map如何根據(jù)key指定條件進(jìn)行過濾篩選問題,具有很好的參考價(jià)值,希望對大家有所幫助,如有錯(cuò)誤或未考慮完全的地方,望不吝賜教
    2023-09-09

最新評論

西林县| 兴文县| 绥宁县| 宽城| 河间市| 昌图县| 铁力市| 淮阳县| 泸水县| 万盛区| 阳春市| 昭通市| 澄城县| 云林县| 南郑县| 中方县| 安吉县| 宁武县| 温宿县| 乐业县| 奈曼旗| 灵台县| 商水县| 肃北| 北海市| 巴彦县| 麦盖提县| 迭部县| 红河县| 巩义市| 太谷县| 青神县| 陈巴尔虎旗| 闻喜县| 东乡县| 札达县| 昆山市| 衡阳县| 伊通| 辉南县| 湄潭县|