Java之反射Reflection

Paste_Image.png

什么是Java的反射

Java反射是可以讓我們?cè)谶\(yùn)行時(shí)獲取類的函數(shù)姐刁,屬性,父類预吆,接口等Class內(nèi)部信息的機(jī)制龙填。通過(guò)反射還可以讓我們?cè)谶\(yùn)行期實(shí)例化對(duì)象,調(diào)用方法拐叉,通過(guò)調(diào)用get/set方法獲取變量的值岩遗,即使方法或?qū)傩允撬接械囊部梢酝ㄟ^(guò)反射的形勢(shì)調(diào)用,這種看透class的能力被稱為內(nèi)省凤瘦,這種能力在框架開(kāi)發(fā)中尤為重要宿礁。有些情況下,我們要使用的類在運(yùn)行時(shí)才會(huì)確定蔬芥,這個(gè)時(shí)候我們不能在編譯器就使用它梆靖,因此只能通過(guò)反射的形勢(shì)來(lái)使用在運(yùn)行才存在的類(該類符合某種特定的規(guī)范,例如JDBC)笔诵,這是反射用得比較多的場(chǎng)景返吻。
還有一個(gè)比較常見(jiàn)的場(chǎng)景就是編譯時(shí)我們對(duì)于類的內(nèi)部信息不可知,必須得到運(yùn)行時(shí)才能獲取類的具體信息乎婿。比如ORM框架测僵,在運(yùn)行時(shí)才能夠獲取類中的各個(gè)屬性,然后通過(guò)反射的形式獲取其屬性名和值,存入數(shù)據(jù)庫(kù)捍靠。這也是反射比較經(jīng)典的應(yīng)用場(chǎng)景之一沐旨。

下面我會(huì)為大家演示反射的一些常用的api,從代碼的角度理解反射榨婆。
反射的相關(guān)api列舉出來(lái):

接口說(shuō)明

<pre>// 加載指定的 Class 對(duì)象磁携,參數(shù) 1 為要加載的類的完整路徑,例如"com.simple.Student". ( 常用方式 )
public static Class<?> forName (String className)

// 加載指定的 Class 對(duì)象良风,參數(shù) 1 為要加載的類的完整路徑谊迄,例如"com.simple.Student";
// 參數(shù) 2 為是否要初始化該 Class 對(duì)象,參數(shù) 3 為指定加載該類的 ClassLoader.
public static Class<?> forName (String className, boolean shouldInitialize, ClassLoader classLoader)</pre>

獲取構(gòu)造函數(shù)接口

<pre>// 獲取一個(gè)公有的構(gòu)造函數(shù)拖吼,參數(shù)為可變參數(shù)鳞上,如果構(gòu)造函數(shù)有參數(shù)这吻,那么需要將參數(shù)的類型傳遞給 getConstructor 方法
public Constructor<T> getConstructor (Class...<?> parameterTypes)
// 獲取目標(biāo)類所有的公有構(gòu)造函數(shù)
public Constructor[]<?> getConstructors ()</pre>

獲取類中的方法接口

<pre>// 獲取 Class 對(duì)象中指定函數(shù)名和參數(shù)的函數(shù)吊档,參數(shù)一為函數(shù)名,參數(shù) 2 為參數(shù)類型列表
public Method getDeclaredMethod (String name, Class...<?> parameterTypes)

// 獲取該 Class 對(duì)象中的所有函數(shù)( 不包含從父類繼承的函數(shù) )
public Method[] getDeclaredMethods ()

// 獲取指定的 Class 對(duì)象中的公有函數(shù)唾糯,參數(shù)一為函數(shù)名怠硼,參數(shù) 2 為參數(shù)類型列表
public Method getMethod (String name, Class...<?> parameterTypes)

// 獲取該 Class 對(duì)象中的所有公有函數(shù) ( 包含從父類和接口類集成下來(lái)的函數(shù) )
public Method[] getMethods ()</pre>

獲取類中的成員屬性接口

<pre>// 獲取 Class 對(duì)象中指定屬性名的屬性,參數(shù)一為屬性名
public Method getDeclaredField (String name)

// 獲取該 Class 對(duì)象中的所有屬性( 不包含從父類繼承的屬性 )
public Method[] getDeclaredFields ()

// 獲取指定的 Class 對(duì)象中的公有屬性移怯,參數(shù)一為屬性名
public Method getField (String name)

// 獲取該 Class 對(duì)象中的所有公有屬性 ( 包含從父類和接口類集成下來(lái)的公有屬性 )
public Method[] getFields ()</pre>

獲取Class對(duì)象

在你想檢查一個(gè)類的信息之前香璃,你首先需要獲取類的 Class 對(duì)象。Java 中的所有類型包括基本類型舟误,即使是數(shù)組都有與之關(guān)聯(lián)的 Class 類的對(duì)象葡秒。如果你在編譯期知道一個(gè)類的名字的話,那么你可以使用如下的方式獲取一個(gè)類的 Class 對(duì)象嵌溢。
<pre>Class<?> myObjectClass = MyObject.class;</pre>
如果你已經(jīng)得到了某個(gè)對(duì)象眯牧,但是你想獲取這個(gè)對(duì)象的 Class 對(duì)象,那么你可以通過(guò)下面的方法得到:
<pre>Student me = new Student("mr.simple");
Class<?> clazz = me.getClass();</pre>
如果你在編譯期獲取不到目標(biāo)類型赖草,但是你知道它的完整類路徑学少,那么你可以通過(guò)如下的形式來(lái)獲取 Class 對(duì)象:
<pre>Class<?> myObjectClass = Class.forName("com.simple.User");</pre>

在使用 Class.forName()方法時(shí),你必須提供一個(gè)類的全名秧骑,這個(gè)全名包括類所在的包的名字版确。例如 User 類位于 com.simple 包,那么他的完整類路徑就是 com.simple.User乎折。如果在調(diào)用 Class.forName()方法時(shí)绒疗,沒(méi)有在編譯路徑下(classpath)找到對(duì)應(yīng)的類,那么將會(huì)拋出 ClassNotFoundException骂澄。

通過(guò)Class對(duì)象構(gòu)造目標(biāo)類型的對(duì)象

一旦你拿到 Class 對(duì)象之后吓蘑,你就可以為所欲為了!當(dāng)你善用它的時(shí)候它就是神兵利器酗洒,當(dāng)你心懷鬼胎之時(shí)它就會(huì)變成惡魔士修。但獲取 Class 對(duì)象只是第一步枷遂,我們需要在執(zhí)行那些強(qiáng)大的行為之前通過(guò) Class 對(duì)象構(gòu)造出該類型的對(duì)象,然后才能通過(guò)該對(duì)象釋放它的能量棋嘲。 我們知道酒唉,在 java 中要構(gòu)造對(duì)象,必須通過(guò)該類的構(gòu)造函數(shù)沸移,那么其實(shí)反射也是一樣一樣的痪伦。但是它們確實(shí)有區(qū)別的,通過(guò)反射構(gòu)造對(duì)象雹锣,我們首先要獲取類的 Constructor(構(gòu)造器)對(duì)象网沾,然后通過(guò) Constructor 來(lái)創(chuàng)建目標(biāo)類的對(duì)象。還是直接上代碼的蕊爵。
<pre> private static void classForName() {
try {
// 獲取 Class 對(duì)象
Class<?> clz = Class.forName("org.java.advance.reflect.Student");
// 通過(guò) Class 對(duì)象獲取 Constructor辉哥,Student 的構(gòu)造函數(shù)有一個(gè)字符串參數(shù)
// 因此這里需要傳遞參數(shù)的類型 ( Student 類見(jiàn)后面的代碼 )
Constructor<?> constructor = clz.getConstructor(String.class);
// 通過(guò) Constructor 來(lái)創(chuàng)建 Student 對(duì)象
Object obj = constructor.newInstance("mr.simple");
System.out.println(" obj : " + obj.toString());
} catch (Exception e) {
e.printStackTrace();
}
}</pre>

Person.java

<pre>public class Person {
String mName;

public Person(String aName) {
    mName = aName;
}

private void sayHello(String friendName) {
    System.out.println(mName + " say hello to " + friendName);
}

protected void showMyName() {
    System.out.println("My name is " + mName);
}

public void breathe() {
    System.out.println(" take breathe ");
}

}</pre>

Student.java

<pre>public class Student extends Person implements Examination {
// 年級(jí)
int mGrade;

public Student(String aName) {
    super(aName);
}

public Student(int grade, String aName) {
    super(aName);
    mGrade = grade;
}

private void learn(String course) {
    System.out.println(mName + " learn " + course);
}

public void takeAnExamination() {
    System.out.println(" takeAnExamination ");
}

public String toString() {
    return " Student :  " + mName;
}</pre>

Examination.java

<pre>// 考試接口
public interface Examination {
public void takeAnExamination();
}</pre>

反射獲取類中定義的方法

要獲取當(dāng)前類中定義的所有方法可以通過(guò) Class 中的 getDeclaredMethods 函數(shù),它會(huì)獲取到當(dāng)前類中的 public攒射、default醋旦、protected、private 的所有方法会放。而 getDeclaredMethod(String name, Class...<?> parameterTypes)則是獲取某個(gè)指定的方法饲齐。代碼示例如下 :
<pre> private static void showDeclaredMethods() {
Student student = new Student("mr.simple");
Method[] methods = student.getClass().getDeclaredMethods();
for (Method method : methods) {
System.out.println("declared method name : " + method.getName());
}

    try {
        Method learnMethod = student.getClass().getDeclaredMethod("learn", String.class);
        // 獲取方法的參數(shù)類型列表
        Class<?>[] paramClasses = learnMethod.getParameterTypes() ;
        for (Class<?> class1 : paramClasses) {
            System.out.println("learn 方法的參數(shù)類型 : " + class1.getName());
        }
        // 是否是 private 函數(shù),屬性是否是 private 也可以使用這種方式判斷
        System.out.println(learnMethod.getName() + " is private "
                + Modifier.isPrivate(learnMethod.getModifiers()));
        learnMethod.invoke(student, "java ---> ");
    } catch (Exception e) {
        e.printStackTrace();
    }
}</pre>

獲取當(dāng)前類咧最,父類中定義的公有方法

要獲取當(dāng)前類以及父類中的所有 public 方法可以通過(guò) Class 中的 getMethods 函數(shù)捂人,而 getMethod 則是獲取某個(gè)指定的方法。代碼示例如下 :
<pre>private static void showMethods() {
Student student = new Student("mr.simple");
// 獲取所有方法
Method[] methods = student.getClass().getMethods();
for (Method method : methods) {
System.out.println("method name : " + method.getName());
}

    try {
        // 通過(guò) getMethod 只能獲取公有方法矢沿,如果獲取私有方法則會(huì)拋出異常滥搭,比如這里就會(huì)拋異常
        Method learnMethod = student.getClass().getMethod("learn", String.class);
        // 是否是 private 函數(shù),屬性是否是 private 也可以使用這種方式判斷
        System.out.println(learnMethod.getName() + " is private " + Modifier.isPrivate(learnMethod.getModifiers()));
        // 調(diào)用 learn 函數(shù)
        learnMethod.invoke(student, "java");
    } catch (Exception e) {
        e.printStackTrace();
    }
}</pre>

這里需要注意的是 getDeclaredMethod 和 getDeclaredMethods 包含 private咨察、protected论熙、default、public 的函數(shù)摄狱,并且通過(guò)這兩個(gè)函數(shù)獲取到的只是在自身中定義的函數(shù)脓诡,從父類中集成的函數(shù)不能夠獲取到。而 getMethod 和 getMethods 只包含 public 函數(shù)媒役,父類中的公有函數(shù)也能夠獲取到祝谚。

反射當(dāng)前類中定義的屬性

要獲取當(dāng)前類中定義的所有屬性可以通過(guò) Class 中的 getDeclaredFields 函數(shù),它會(huì)獲取到當(dāng)前類中的 public酣衷、default交惯、protected、private 的所有屬性。而 getDeclaredField 則是獲取某個(gè)指定的屬性席爽。代碼示例如下 :
<pre>private static void showDeclaredFields() {
Student student = new Student("mr.simple");
// 獲取當(dāng)前類和父類的所有公有屬性
Field[] publicFields = student.getClass().getDeclaredFields();
for (Field field : publicFields) {
System.out.println("declared field name : " + field.getName());
}

    try {
        // 獲取當(dāng)前類和父類的某個(gè)公有屬性
        Field gradeField = student.getClass().getDeclaredField("mGrade");
        // 獲取屬性值
        System.out.println(" my grade is : " + gradeField.getInt(student));
        // 設(shè)置屬性值
        gradeField.set(student, 10);
        System.out.println(" my grade is : " + gradeField.getInt(student));
    } catch (Exception e) {
        e.printStackTrace();
    }
}</pre>

獲取當(dāng)前類意荤、父類中定義的公有屬性

要獲取當(dāng)前類以及父類中的所有 public 屬性可以通過(guò) Class 中的 getFields 函數(shù),而 getField 則是獲取某個(gè)指定的屬性只锻。代碼示例如下 :
<pre> private static void showFields() {
Student student = new Student("mr.simple");
// 獲取當(dāng)前類和父類的所有公有屬性
Field[] publicFields = student.getClass().getFields();
for (Field field : publicFields) {
System.out.println("field name : " + field.getName());
}

    try {
        // 獲取當(dāng)前類和父類的某個(gè)公有屬性
        Field ageField = student.getClass().getField("mAge");
        System.out.println(" age is : " + ageField.getInt(student));
    } catch (Exception e) {
        e.printStackTrace();
    }
}</pre>

這里需要注意的是 getDeclaredField 和 getDeclaredFields 包含 private玖像、protected、default齐饮、public 的屬性捐寥,并且通過(guò)這兩個(gè)函數(shù)獲取到的只是在自身中定義的屬性,從父類中集成的屬性不能夠獲取到祖驱。而 getField 和 getFields 只包含 public 屬性握恳,父類中的公有屬性也能夠獲取到。

獲取Class對(duì)象中實(shí)現(xiàn)的接口

<pre>private static void showInterfaces() {
Student student = new Student("mr.simple");
Class<?>[] interfaceses = student.getClass().getInterfaces();
for (Class<?> class1 : interfaceses) {
System.out.println("Student's interface is : " + class1.getName());
}
}</pre>

獲取Class對(duì)象的父類

<pre>Student student = new Student("mr.simple");
Class<?> superClass = student.getClass().getSuperclass();
while (superClass != null) {
System.out.println("Student's super class is : " + superClass.getName());
// 再獲取父類的上一層父類捺僻,直到最后的 Object 類乡洼,Object 的父類為 null
superClass = superClass.getSuperclass();
}</pre>

最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市陵像,隨后出現(xiàn)的幾起案子就珠,更是在濱河造成了極大的恐慌寇壳,老刑警劉巖醒颖,帶你破解...
    沈念sama閱讀 222,252評(píng)論 6 516
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異壳炎,居然都是意外死亡泞歉,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 94,886評(píng)論 3 399
  • 文/潘曉璐 我一進(jìn)店門(mén)匿辩,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)腰耙,“玉大人,你說(shuō)我怎么就攤上這事铲球⊥ε樱” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 168,814評(píng)論 0 361
  • 文/不壞的土叔 我叫張陵稼病,是天一觀的道長(zhǎng)选侨。 經(jīng)常有香客問(wèn)我,道長(zhǎng)然走,這世上最難降的妖魔是什么援制? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 59,869評(píng)論 1 299
  • 正文 為了忘掉前任,我火速辦了婚禮芍瑞,結(jié)果婚禮上晨仑,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好洪己,可當(dāng)我...
    茶點(diǎn)故事閱讀 68,888評(píng)論 6 398
  • 文/花漫 我一把揭開(kāi)白布妥凳。 她就那樣靜靜地躺著,像睡著了一般答捕。 火紅的嫁衣襯著肌膚如雪猾封。 梳的紋絲不亂的頭發(fā)上,一...
    開(kāi)封第一講書(shū)人閱讀 52,475評(píng)論 1 312
  • 那天噪珊,我揣著相機(jī)與錄音晌缘,去河邊找鬼。 笑死痢站,一個(gè)胖子當(dāng)著我的面吹牛磷箕,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播阵难,決...
    沈念sama閱讀 41,010評(píng)論 3 422
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼岳枷,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了呜叫?” 一聲冷哼從身側(cè)響起空繁,我...
    開(kāi)封第一講書(shū)人閱讀 39,924評(píng)論 0 277
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎朱庆,沒(méi)想到半個(gè)月后盛泡,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 46,469評(píng)論 1 319
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡娱颊,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 38,552評(píng)論 3 342
  • 正文 我和宋清朗相戀三年傲诵,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片箱硕。...
    茶點(diǎn)故事閱讀 40,680評(píng)論 1 353
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡拴竹,死狀恐怖,靈堂內(nèi)的尸體忽然破棺而出剧罩,到底是詐尸還是另有隱情栓拜,我是刑警寧澤,帶...
    沈念sama閱讀 36,362評(píng)論 5 351
  • 正文 年R本政府宣布惠昔,位于F島的核電站幕与,受9級(jí)特大地震影響,放射性物質(zhì)發(fā)生泄漏舰罚。R本人自食惡果不足惜纽门,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 42,037評(píng)論 3 335
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望营罢。 院中可真熱鬧赏陵,春花似錦饼齿、人聲如沸。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 32,519評(píng)論 0 25
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)。三九已至吃型,卻和暖如春证鸥,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背勤晚。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 33,621評(píng)論 1 274
  • 我被黑心中介騙來(lái)泰國(guó)打工枉层, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人赐写。 一個(gè)月前我還...
    沈念sama閱讀 49,099評(píng)論 3 378
  • 正文 我出身青樓鸟蜡,卻偏偏與公主長(zhǎng)得像,于是被迫代替她去往敵國(guó)和親挺邀。 傳聞我的和親對(duì)象是個(gè)殘疾皇子揉忘,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 45,691評(píng)論 2 361

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

  • Spring Cloud為開(kāi)發(fā)人員提供了快速構(gòu)建分布式系統(tǒng)中一些常見(jiàn)模式的工具(例如配置管理,服務(wù)發(fā)現(xiàn)端铛,斷路器泣矛,智...
    卡卡羅2017閱讀 134,713評(píng)論 18 139
  • 1. 了解 Java 中的反射 1.1 什么是 Java 的反射 Java 反射是可以讓我們?cè)谶\(yùn)行時(shí)獲取類的函數(shù)、...
    Ten_Minutes閱讀 541評(píng)論 0 4
  • 1. Java基礎(chǔ)部分 基礎(chǔ)部分的順序:基本語(yǔ)法禾蚕,類相關(guān)的語(yǔ)法您朽,內(nèi)部類的語(yǔ)法,繼承相關(guān)的語(yǔ)法夕膀,異常的語(yǔ)法虚倒,線程的語(yǔ)...
    子非魚(yú)_t_閱讀 31,664評(píng)論 18 399
  • 一:java概述:1,JDK:Java Development Kit产舞,java的開(kāi)發(fā)和運(yùn)行環(huán)境,java的開(kāi)發(fā)工...
    ZaneInTheSun閱讀 2,661評(píng)論 0 11
  • 【墨蘭】 墨蝶旋翼舞蓮蓮菠剩, 盈姿裊裊騰云天 易猫。 絳唇微啟鍍春色, 幽吐蘭香攝玄月 具壮。
    茵夢(mèng)湖蘭閱讀 772評(píng)論 0 2