Java反射

反射.png

概述

定義

Java反射機(jī)制是在運(yùn)行狀態(tài)中笆制,對(duì)于任意一個(gè)類叫搁,都能夠知道這個(gè)類的所有屬性和方法匈仗;對(duì)于任意一個(gè)對(duì)象,都能夠調(diào)用它的任意方法和屬性悍手。這種動(dòng)態(tài)獲取信息以及動(dòng)態(tài)調(diào)用對(duì)象方法的功能稱為Java語(yǔ)言的反射機(jī)制帘睦。

用途

通過反射,Java 代碼可以發(fā)現(xiàn)有關(guān)已加載類的字段坦康,方法和構(gòu)造函數(shù)的信息竣付,并可以在安全限制內(nèi)對(duì)這些字段,方法和構(gòu)造函數(shù)進(jìn)行操作滞欠。

很多人都認(rèn)為反射在實(shí)際Java中開發(fā)應(yīng)用中并不廣泛卑笨,其實(shí)不然。當(dāng)我們?cè)谑褂?IDE(如 IDEA/Eclipse)時(shí)仑撞,當(dāng)我們輸入一個(gè)對(duì)象或者類并調(diào)用它的屬性和方法時(shí)赤兴,一按 (“.”)點(diǎn)號(hào),編譯器就會(huì)自動(dòng)列出她的屬性或方法隧哮,這里就會(huì)用到反射桶良。

反射最重要的用途就是開發(fā)各種通用框架

很多框架(比如 Spring)都是配置化的(比如Spring 通過 XML 配置模式裝載 Bean),為了保證框架的通用性沮翔,他們可能根據(jù)配置文件加載不同的對(duì)象或類陨帆,調(diào)用不同的方法,這個(gè)時(shí)候就必須用到反射——運(yùn)行時(shí)動(dòng)態(tài)加載需要加載的對(duì)象采蚀。

對(duì)于框架開發(fā)人員來(lái)說(shuō)疲牵,反射作用非常大,它是各種容器實(shí)現(xiàn)的核心榆鼠。而對(duì)于一般的開發(fā)者來(lái)說(shuō)挤庇,不深入框架開發(fā)反射用的就會(huì)少一點(diǎn)群井,不過了解一下框架的底層機(jī)制有助于豐富自己的編程思想锌俱,也是很有益的迎膜。

Java反射框架提供一下功能:

  • 在運(yùn)行時(shí)判定任意一個(gè)對(duì)象所屬的類
  • 在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象
  • 在運(yùn)行時(shí)判定任意一個(gè)類所具有的成員變量和方法
  • 在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法

反射的優(yōu)缺點(diǎn)

反射的優(yōu)點(diǎn)

使用反射機(jī)制,代碼可以在運(yùn)行時(shí)裝配神妹,提高了程序的靈活性和擴(kuò)展性颓哮,降低耦合性,提高自適應(yīng)能力鸵荠。它允許程序創(chuàng)建和控制任何類的對(duì)象冕茅,無(wú)需硬編碼目標(biāo)類

反射的缺點(diǎn)

性能問題:使用反射基本上是一種解釋操作,JVM無(wú)法對(duì)這些代碼進(jìn)行優(yōu)化,因此姨伤,反射操作的效率要比那些非反射操作低得多哨坪。反射機(jī)制主要應(yīng)用在對(duì)靈活性和擴(kuò)展性要求很高的系統(tǒng)框架上,對(duì)性能要求高的程序中不建議使用

安全限制:使用反射技術(shù)要求程序必須在一個(gè)沒有安全限制的環(huán)境中運(yùn)行

內(nèi)部暴露:由于反射允許代碼執(zhí)行一些在正常情況下不被允許的操作(比如訪問私有的屬性和方法)姜挺,所以使用反射可能會(huì)導(dǎo)致意料之外的副作用——代碼有功能上的錯(cuò)誤齿税,降低可移植性彼硫。反射代碼破壞了抽象性炊豪,因此當(dāng)平臺(tái)發(fā)生改變的時(shí)候,代碼的行為就有可能也隨著變化拧篮。

反射機(jī)制的相關(guān)類

與Java反射相關(guān)的類如下:

類名 用途
Class類 代表類的實(shí)體词渤,在運(yùn)行的Java應(yīng)用程序中表示類和接口
Field類 代表類的成員變量(成員變量也稱為類的屬性)
Method類 代表類的方法
Constructor類 代表類的構(gòu)造方法

Class類

Class代表類的實(shí)體,在運(yùn)行的Java應(yīng)用程序中表示類和接口串绩。在這個(gè)類中提供了很多有用的方法缺虐,這里對(duì)他們簡(jiǎn)單的分類介紹。

  • 獲得類相關(guān)的方法
方法 用途
asSubclass(Class<U> clazz) 把傳遞的類的對(duì)象轉(zhuǎn)換成代表其子類的對(duì)象
Cast 把對(duì)象轉(zhuǎn)換成代表類或是接口的對(duì)象
getClassLoader() 獲得類的加載器
getClasses() 返回一個(gè)數(shù)組礁凡,數(shù)組中包含該類中所有公共類和接口類的對(duì)象
getDeclaredClasses() 返回一個(gè)數(shù)組高氮,數(shù)組中包含該類中所有類和接口類的對(duì)象
forName(String className) 根據(jù)類名返回類的對(duì)象
getName() 獲得類的完整路徑名字
newInstance() 創(chuàng)建類的實(shí)例
getPackage() 獲得類的包
getSimpleName() 獲得類的名字
getSuperclass() 獲得當(dāng)前類繼承的父類的名字
getInterfaces() 獲得當(dāng)前類實(shí)現(xiàn)的類或是接口
  • 獲得類中屬性相關(guān)的方法
方法 用途
getField(String name) 獲得某個(gè)公有的屬性對(duì)象
getFields() 獲得所有公有的屬性對(duì)象
getDeclaredField(String name) 獲得某個(gè)屬性對(duì)象
getDeclaredFields() 獲得所有屬性對(duì)象
  • 獲得類中注解相關(guān)的方法
方法 用途
getAnnotation(Class<A> annotationClass) 返回該類中與參數(shù)類型匹配的公有注解對(duì)象
getAnnotations() 返回該類所有的公有注解對(duì)象
getDeclaredAnnotation(Class<A> annotationClass) 返回該類中與參數(shù)類型匹配的所有注解對(duì)象
getDeclaredAnnotations() 返回該類所有的注解對(duì)象
  • 獲得類中構(gòu)造器相關(guān)的方法
方法 用途
getConstructor(Class...<?> parameterTypes) 獲得該類中與參數(shù)類型匹配的公有構(gòu)造方法
getConstructors() 獲得該類的所有公有構(gòu)造方法
getDeclaredConstructor(Class...<?> parameterTypes) 獲得該類中與參數(shù)類型匹配的構(gòu)造方法
getDeclaredConstructors() 獲得該類所有構(gòu)造方法
  • 獲得類中方法相關(guān)的方法
方法 用途
getMethod(String name, Class...<?> parameterTypes) 獲得該類某個(gè)公有的方法
getMethods() 獲得該類所有公有的方法
getDeclaredMethod(String name, Class...<?> parameterTypes) 獲得該類某個(gè)方法
getDeclaredMethods() 獲得該類所有方法
  • 類中其他重要的方法
方法 用途
isAnnotation() 如果是注解類型則返回true
isAnnotationPresent(Class<? extends Annotation> annotationClass) 如果是指定類型注解類型則返回true
isAnonymousClass() 如果是匿名類則返回true
isArray() 如果是一個(gè)數(shù)組類則返回true
isEnum() 如果是枚舉類則返回true
isInstance(Object obj) 如果obj是該類的實(shí)例則返回true
isInterface() 如果是接口類則返回true
isLocalClass() 如果是局部類則返回true
isMemberClass() 如果是內(nèi)部類則返回true

Field類

Field代表類的成員變量(成員變量也稱為類的屬性)。

方法 用途
equals(Object obj) 屬性與obj相等則返回true
get(Object obj) 獲得obj中對(duì)應(yīng)的屬性值
set(Object obj, Object value) 設(shè)置obj中對(duì)應(yīng)屬性值

Method類

Method代表類的方法顷牌。

方法 用途
invoke(Object obj, Object... args) 傳遞object對(duì)象及參數(shù)調(diào)用該對(duì)象對(duì)應(yīng)的方法

Constructor類

Constructor代表類的構(gòu)造方法剪芍。

方法 用途
newInstance(Object... initargs) 根據(jù)傳遞的參數(shù)創(chuàng)建類的對(duì)象

示例

為了演示反射的使用,首先構(gòu)造一個(gè)與書籍相關(guān)的model——Book.java窟蓝,然后了解獲取Class類對(duì)象的三種方法罪裹,最后通過反射方法示例創(chuàng)建對(duì)象、反射私有構(gòu)造方法运挫、反射私有屬性状共、反射私有方法

被反射類Book.java

public class Book{
    private final static String TAG = "BookTag";

    private String name;
    private String author;

    @Override
    public String toString() {
        return "Book{" +
                "name='" + name + '\'' +
                ", author='" + author + '\'' +
                '}';
    }

    public Book() {
    }

    private Book(String name, String author) {
        this.name = name;
        this.author = author;
    }

    public String getName() {
        return name;
    }

    public void setName(String name) {
        this.name = name;
    }

    public String getAuthor() {
        return author;
    }

    public void setAuthor(String author) {
        this.author = author;
    }

    private String declaredMethod(int index) {
        String string = null;
        switch (index) {
            case 0:
                string = "I am declaredMethod 0 !";
                break;
            case 1:
                string = "I am declaredMethod 1 !";
                break;
            default:
                string = "I am declaredMethod -1 !";
        }

        return string;
    }
}

獲取Class類對(duì)象的三種方法

在反射中,要獲取一個(gè)類或調(diào)用一個(gè)類的方法谁帕,我們首先需要獲取到該類的 Class 對(duì)象峡继。
在 Java API 中,獲取 Class 類對(duì)象的三種方法
方法一:使用 Class.forName 靜態(tài)方法匈挖。當(dāng)你知道該類的全路徑名時(shí)鬓椭,你可以使用該方法獲取 Class 類對(duì)象。但可能拋出 ClassNotFoundException 異常
Class<?> classBook = Class.forName("com.jourwon.reflect.Book");

方法二:這種方法只適合在編譯前就知道操作的 Class关划。直接通過 類名.class 的方式得到小染,該方法最為安全可靠,程序性能更高贮折,這說(shuō)明任何一個(gè)類都有一個(gè)隱含的靜態(tài)成員變量 class
Class clz = Book.class;

方法三:使用類對(duì)象的 getClass() 方法裤翩。
Book book1 = new Book();
Class<? extends Book> book1Class = book1.getClass();

@Test
public void getClz() {
    try {
        // 方法一,使用 Class.forName 靜態(tài)方法
        Class<?> classBook = Class.forName("com.jourwon.reflect.Book");

        // 方法二:直接通過 類名.class 的方式得到
        Class clz = Book.class;

        // 方法三:使用類對(duì)象的 getClass() 方法。
        Book book1 = new Book();
        Class<? extends Book> book1Class = book1.getClass();

        System.out.println(classBook == clz);
        System.out.println(classBook == book1Class);

    } catch (Exception ex) {
        ex.printStackTrace();
    }
}

輸出結(jié)果都是true踊赠,可以知道三種方法獲取到的Class對(duì)象都是同一個(gè)對(duì)象

true
true

反射常用類和方法測(cè)試

public class ReflectClass {

    private static final Logger log = LoggerFactory.getLogger(ReflectClass.class);

    // 創(chuàng)建對(duì)象
    @Test
    public void reflectNewInstance() {
        try {
            Class<?> classBook = Class.forName("com.jourwon.reflect.Book");

            Object objectBook = classBook.newInstance();
            Book book = (Book) objectBook;
            book.setName("Java高級(jí)特性-反射-創(chuàng)建對(duì)象");
            book.setAuthor("JourWon");
            log.info(book.toString());

        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    // 反射私有的構(gòu)造方法
    @Test
    public void reflectPrivateConstructor() {
        try {
            Class<?> classBook = Class.forName("com.jourwon.reflect.Book");
            Constructor<?> declaredConstructorBook = classBook.getDeclaredConstructor(String.class, String.class);
            // 暴力反射
            declaredConstructorBook.setAccessible(true);
            Object objectBook = declaredConstructorBook.newInstance("Java高級(jí)特性-反射-反射私有的構(gòu)造方法", "JourWon");
            Book book = (Book) objectBook;
            log.info(book.toString());
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }

    // 反射私有屬性
    @Test
    public void reflectPrivateField() {
        try {
            Class<?> classBook = Class.forName("com.jourwon.reflect.Book");
            Object objectBook = classBook.newInstance();
            Field fieldTag = classBook.getDeclaredField("TAG");
            fieldTag.setAccessible(true);
            String tag = (String) fieldTag.get(objectBook);
            log.info(tag);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }


    // 反射私有方法
    @Test
    public void reflectPrivateMethod() {
        try {
            Class<?> classBook = Class.forName("com.jourwon.reflect.Book");
            Method methodBook = classBook.getDeclaredMethod("declaredMethod", int.class);
            methodBook.setAccessible(true);
            Object objectBook = classBook.newInstance();
            String string = (String) methodBook.invoke(objectBook, 0);

            ReflectClass.

            log.info(string);
        } catch (Exception ex) {
            ex.printStackTrace();
        }
    }


}

輸出結(jié)果

[main] INFO com.jourwon.reflect.ReflectClass - Book{name='Java高級(jí)特性-反射-創(chuàng)建對(duì)象', author='JourWon'}

[main] INFO com.jourwon.reflect.ReflectClass - Book{name='Java高級(jí)特性-反射-反射私有的構(gòu)造方法', author='JourWon'}

[main] INFO com.jourwon.reflect.ReflectClass - BookTag

[main] INFO com.jourwon.reflect.ReflectClass - I am declaredMethod 0 ! 

通過反射獲取私有屬性呵扛,方法和構(gòu)造方法時(shí),需要進(jìn)行暴力反射筐带,設(shè)置setAccessible(true)今穿。否則會(huì)報(bào)錯(cuò)說(shuō)無(wú)法獲取私有屬性,方法和構(gòu)造方法

總結(jié)

本文列舉了反射機(jī)制使用過程中常用的伦籍、重要的一些類及其方法蓝晒,更多信息和用法,反射原理和源碼分析需要近一步的閱讀反射相關(guān)資料帖鸦。

在閱讀Class類文檔時(shí)發(fā)現(xiàn)一個(gè)特點(diǎn)芝薇,以通過反射獲得Method對(duì)象為例,一般會(huì)提供四種方法作儿,getMethod(parameterTypes)洛二、getMethods()、getDeclaredMethod(parameterTypes)和getDeclaredMethods()攻锰。getMethod(parameterTypes)用來(lái)獲取某個(gè)公有的方法的對(duì)象晾嘶,getMethods()獲得該類所有公有的方法,getDeclaredMethod(parameterTypes)獲得該類某個(gè)方法娶吞,getDeclaredMethods()獲得該類所有方法垒迂。帶有Declared修飾的方法可以反射到私有的方法,沒有Declared修飾的只能用來(lái)反射公有的方法寝志。其他的Annotation娇斑、Field、Constructor也是如此材部。

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末毫缆,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子乐导,更是在濱河造成了極大的恐慌苦丁,老刑警劉巖,帶你破解...
    沈念sama閱讀 221,576評(píng)論 6 515
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件物臂,死亡現(xiàn)場(chǎng)離奇詭異旺拉,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)棵磷,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,515評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門蛾狗,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái),“玉大人仪媒,你說(shuō)我怎么就攤上這事沉桌。” “怎么了?”我有些...
    開封第一講書人閱讀 168,017評(píng)論 0 360
  • 文/不壞的土叔 我叫張陵留凭,是天一觀的道長(zhǎng)佃扼。 經(jīng)常有香客問我,道長(zhǎng)蔼夜,這世上最難降的妖魔是什么兼耀? 我笑而不...
    開封第一講書人閱讀 59,626評(píng)論 1 296
  • 正文 為了忘掉前任,我火速辦了婚禮求冷,結(jié)果婚禮上瘤运,老公的妹妹穿的比我還像新娘。我一直安慰自己遵倦,他們只是感情好尽超,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,625評(píng)論 6 397
  • 文/花漫 我一把揭開白布官撼。 她就那樣靜靜地躺著梧躺,像睡著了一般。 火紅的嫁衣襯著肌膚如雪傲绣。 梳的紋絲不亂的頭發(fā)上掠哥,一...
    開封第一講書人閱讀 52,255評(píng)論 1 308
  • 那天,我揣著相機(jī)與錄音秃诵,去河邊找鬼续搀。 笑死,一個(gè)胖子當(dāng)著我的面吹牛菠净,可吹牛的內(nèi)容都是我干的禁舷。 我是一名探鬼主播,決...
    沈念sama閱讀 40,825評(píng)論 3 421
  • 文/蒼蘭香墨 我猛地睜開眼毅往,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼牵咙!你這毒婦竟也來(lái)了?” 一聲冷哼從身側(cè)響起攀唯,我...
    開封第一講書人閱讀 39,729評(píng)論 0 276
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤洁桌,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后侯嘀,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體另凌,經(jīng)...
    沈念sama閱讀 46,271評(píng)論 1 320
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,363評(píng)論 3 340
  • 正文 我和宋清朗相戀三年戒幔,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了吠谢。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,498評(píng)論 1 352
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡诗茎,死狀恐怖工坊,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤栅组,帶...
    沈念sama閱讀 36,183評(píng)論 5 350
  • 正文 年R本政府宣布雀瓢,位于F島的核電站,受9級(jí)特大地震影響玉掸,放射性物質(zhì)發(fā)生泄漏刃麸。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,867評(píng)論 3 333
  • 文/蒙蒙 一司浪、第九天 我趴在偏房一處隱蔽的房頂上張望泊业。 院中可真熱鬧,春花似錦啊易、人聲如沸吁伺。這莊子的主人今日做“春日...
    開封第一講書人閱讀 32,338評(píng)論 0 24
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)篮奄。三九已至,卻和暖如春割去,著一層夾襖步出監(jiān)牢的瞬間窟却,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,458評(píng)論 1 272
  • 我被黑心中介騙來(lái)泰國(guó)打工呻逆, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留夸赫,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,906評(píng)論 3 376
  • 正文 我出身青樓咖城,卻偏偏與公主長(zhǎng)得像茬腿,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子宜雀,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,507評(píng)論 2 359

推薦閱讀更多精彩內(nèi)容

  • 類加載機(jī)制 1 什么是反射 Java反射機(jī)制是在運(yùn)行狀態(tài)中對(duì)于任意一個(gè)類切平,都能知道這個(gè)類的所以屬性和方法;對(duì)于任何...
    凱玲之戀閱讀 13,841評(píng)論 3 28
  • 1. 了解 Java 中的反射 1.1 什么是 Java 的反射 Java 反射是可以讓我們?cè)谶\(yùn)行時(shí)獲取類的函數(shù)州袒、...
    Ten_Minutes閱讀 541評(píng)論 0 4
  • 一揭绑、概述 Java反射機(jī)制定義 Java反射機(jī)制是在運(yùn)行狀態(tài)中,對(duì)于任意一個(gè)類郎哭,都能夠知道這個(gè)類中的所有屬性和方法...
    CoderZS閱讀 1,642評(píng)論 0 26
  • 一他匪、概述 1、Java反射機(jī)制(Java-Reflect): 在運(yùn)行狀態(tài)中夸研,對(duì)于任意一個(gè)類邦蜜,都能夠知道這個(gè)類中的所...
    年少懵懂丶流年夢(mèng)閱讀 4,429評(píng)論 0 5
  • 經(jīng)常有人跟我說(shuō):做微商萬(wàn)一虧了怎么辦?萬(wàn)一不成功怎么辦亥至? 我想說(shuō)的是:萬(wàn)一你睡覺地震房子倒了怎么辦悼沈?你干嘛不趕緊搬...
    珍珍_03b1閱讀 273評(píng)論 0 1