Java反射學(xué)習(xí)(一)

原文地址
題主剛學(xué)Java的時(shí)候就了解過(guò)Java反射,但是在實(shí)踐開(kāi)發(fā)中使用的并不是很多矫付,所以也一直未深入了解過(guò)炫乓,最近在看一些公司內(nèi)部框架的源碼,發(fā)現(xiàn)了很多功能都是通過(guò)Java反射來(lái)實(shí)現(xiàn)的钥屈。 本篇文章主要介紹Java反射的基本知識(shí),以供自己日后查閱坝辫。先介紹一下Java反射的定義

JAVA反射機(jī)制是在運(yùn)行狀態(tài)中篷就,對(duì)于任意一個(gè)類,都能夠知道這個(gè)類的所有屬性和方法近忙;對(duì)于任意一個(gè)對(duì)象竭业,都能夠調(diào)用它的任意一個(gè)方法;這種動(dòng)態(tài)獲取的信息以及動(dòng)態(tài)調(diào)用對(duì)象的方法的功能稱為java語(yǔ)言的反射機(jī)制及舍。
Java反射的核心是JVM在運(yùn)行時(shí)才動(dòng)態(tài)加載類或調(diào)用方法/訪問(wèn)屬性未辆,它在編譯期不需要知道運(yùn)行的對(duì)象是誰(shuí),Java反射實(shí)際操作對(duì)象是.class文件(字節(jié)碼文件)

獲得Class對(duì)象

1.通過(guò)Class類的forName靜態(tài)方法锯玛,JDBC開(kāi)發(fā)中常用此方法加載驅(qū)動(dòng)

Class<?> c1 = Class.forName("java.lang.Integer");

2.通過(guò)調(diào)用對(duì)象的getClass()方法

Integer i1 = 1;
Class<?> c2 = i1.getClass();

3.直接獲取類的class

Class<?> c3 = Integer.class;

判斷是否為某個(gè)類的實(shí)例

判斷是否是某個(gè)類的實(shí)例一般用instanceof關(guān)鍵字咐柜,同時(shí)我們也可借助Class對(duì)象的isInstance()方法來(lái)判斷,如下面的代碼

Object obj = "Java";
// 使用instanceof關(guān)鍵字
System.out.println(obj instanceof  String);
// 使用isInstance方法
System.out.println(String.class.isInstance(obj));

isInstance()方法是一個(gè)native方法,它的方法簽名如下:

public native boolean isInstance(Object obj);

創(chuàng)建實(shí)例

通過(guò)Java反射創(chuàng)建對(duì)象有兩種方法:
1.通過(guò)Class對(duì)象的newInstance方法來(lái)創(chuàng)建Class對(duì)象對(duì)應(yīng)的實(shí)例

Class<?> c = String.class;
Object s = c.newInstance();

2.先通過(guò)Class對(duì)象獲取指定的Constructor對(duì)象炕桨,再調(diào)用Constructor對(duì)象的newInstance方法來(lái)創(chuàng)建對(duì)象的實(shí)例,通過(guò)這種方法可以指定構(gòu)造器來(lái)構(gòu)造對(duì)象肯腕。

Class<?> cc = String.class;
Constructor constructor =  cc.getConstructor(String.class);
Object ss = constructor.newInstance("Java");
System.out.println(ss);

獲取類名及變量

直接調(diào)用Class對(duì)象的getName()即可獲取類名(包含package)

Class<?> c = String.class;
System.out.println(c.getName());

獲取類的變量有下面兩種方法
1.通過(guò)Class對(duì)象的getField方法獲取類的所有變量献宫,需要注意是getField()會(huì)獲取該類及其父類的全部公有變量

// Book是自定義的類
Class<?> c = Book.class;
Field[] fields = c.getFields();

2.如果還想獲取對(duì)象的私有變量,可以通過(guò)getDeclaredFields()方法实撒,該方法會(huì)返回該類的所有變量姊途,不論訪問(wèn)權(quán)限

// Book是自定義的類
Class<?> c = Book.class;
Field[] fields = c.getDeclaredFields();
for (Field field : fields) {
    // 獲取訪問(wèn)權(quán)限
    System.out.println(field.getModifiers());
    // 獲取變量類型及名稱
    System.out.println(field.getType() + " " + field.getName());
}

獲取方法

獲取某個(gè)Class對(duì)象的方法,主要有以下幾種方法:
1.getDeclaredMethods方法返回類或接口聲明的所有方法知态,包括公共捷兰、保護(hù)、默認(rèn)訪問(wèn)和私有方法负敏,但不包括繼續(xù)的方法贡茅。

public Method[] getDeclaredMethods() throws SecurityException

2.getMethods,返回該類所有的公共的方法以及繼續(xù)的類公用方法

public Method[] getMethods() throws SecurityException 

3.getMethod返回一個(gè)特定的方法其做,第一個(gè)參數(shù)為方法名稱顶考,后面的參數(shù)是方法參數(shù)對(duì)應(yīng)的Class對(duì)象

public Method getMethod(String name, Class<?>... parameterTypes)

獲取Class對(duì)象的具體列子

Class<?> cc = Book.class;
Method[] methods = cc.getMethods();
for (Method method : methods) {
    //獲取并輸出方法的訪問(wèn)權(quán)限(Modifiers:修飾符)
    int modifiers = method.getModifiers();
    System.out.print(Modifier.toString(modifiers) + " ");
    //獲取并輸出方法的返回值類型
    Class returnType = method.getReturnType();
    System.out.print(returnType.getName() + " " + method.getName() + "( ");
    //獲取并輸出方法的所有參數(shù)
    Parameter[] parameters = method.getParameters();
    for (Parameter parameter: parameters) {
        System.out.print(parameter.getType().getName() + " " + parameter.getName() + ",");
    }
    //獲取并輸出方法拋出的異常
    Class[] exceptionTypes = method.getExceptionTypes();
    if (exceptionTypes.length == 0){
        System.out.println(" )");
    } else {
        for (Class c : exceptionTypes) {
            System.out.println(" ) throws " + c.getName());
        }
    }
}

獲取構(gòu)造器

通過(guò)getConstructor方法可以獲取Class對(duì)象的構(gòu)造器,具體的例子在上文創(chuàng)建實(shí)例中已經(jīng)介紹過(guò)妖泄,在此不再贅述

調(diào)用方法

當(dāng)我們從一個(gè)類獲取到方法之后驹沿,可以用invoke()方法來(lái)調(diào)用這個(gè)方法。invoke方法的簽名如下:

public Object invoke(Object obj, Object... args) throws IllegalAccessException, IllegalArgumentException,
InvocationTargetException

invoke具體的例子:

public class Client {
    public static void main(String[] args) throws Exception {
        Class<?> c = Calculation.class;
        Object obj = c.newInstance();
        Method method = c.getMethod("add", int.class, int.class);
        int res = (int) method.invoke(obj, 1, 2);
        System.out.println(res);
    }
}
class Calculation {
    public int add(int x, int y) {
        return x + y;
    }
}

獲取注解

首先介紹一下注解蹈胡,注解是Java5中的新特性渊季,它是插入你代碼中的一種注釋或者說(shuō)是一種元數(shù)據(jù)(meta data)。這些注解信息可以在編譯期使用預(yù)編譯工具進(jìn)行處理罚渐,也可以在運(yùn)行期使用Java反射機(jī)制進(jìn)行處理却汉。注解可以分為以下四種:

  • 類注解
  • 方法注解
  • 變量注解
  • 參數(shù)注解
    由于篇幅限制,在此只介紹獲取類的注解荷并,其它注解的獲取可以參考:Java Reflection(八):注解
public class Client {
    public static void main(String[] args) throws Exception {
        Class<?> c = Calculation.class;
        // 獲取所有注解
        // Annotation[] annotations = c.getAnnotations();
        // 指定獲取MyAnnotation注解
        Annotation annotation = c.getAnnotation(MyAnnotation.class);
        if (annotation instanceof MyAnnotation) {
            MyAnnotation myAnnotation = (MyAnnotation) annotation;
            System.out.println(myAnnotation.id());
            System.out.println(myAnnotation.desc());
        }
    }
}

@MyAnnotation(id ="1", desc = "calc")
class Calculation {
    public int add(int x, int y) {
        return x + y;
    }
}

// 自定義注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyAnnotation {
    public String id();
    public String desc();
}

Java反射用途

上文都是介紹java反射的基本用法病涨,在業(yè)務(wù)開(kāi)發(fā)確實(shí)很少使用反射,但是優(yōu)秀的框架必然會(huì)使用到反射來(lái)實(shí)現(xiàn)很多復(fù)雜的功能璧坟,比如Spring的IOC(控制反轉(zhuǎn))既穆,通過(guò)解析bean的xml文件,Spring在運(yùn)行期根據(jù)xml配置雀鹃,通過(guò)Java反射生成相應(yīng)的bean幻工,放入到Spring容器中。

Java反射的功能

  • 獲取一個(gè)對(duì)象的類信息.
  • 獲取一個(gè)類的訪問(wèn)修飾符黎茎、成員囊颅、方法、構(gòu)造方法以及超類的信息.
  • 檢獲屬于一個(gè)接口的常量和方法聲明.
  • 創(chuàng)建一個(gè)直到程序運(yùn)行期間才知道名字的類的實(shí)例.
  • 獲取并設(shè)置一個(gè)對(duì)象的成員,甚至這個(gè)成員的名字是在程序運(yùn)行期間才知道.
  • 檢測(cè)一個(gè)在運(yùn)行期間才知道名字的對(duì)象的方法

參考資料

?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末踢代,一起剝皮案震驚了整個(gè)濱河市盲憎,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌胳挎,老刑警劉巖饼疙,帶你破解...
    沈念sama閱讀 216,372評(píng)論 6 498
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場(chǎng)離奇詭異慕爬,居然都是意外死亡窑眯,警方通過(guò)查閱死者的電腦和手機(jī),發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,368評(píng)論 3 392
  • 文/潘曉璐 我一進(jìn)店門(mén)医窿,熙熙樓的掌柜王于貴愁眉苦臉地迎上來(lái)磅甩,“玉大人,你說(shuō)我怎么就攤上這事姥卢【硪” “怎么了?”我有些...
    開(kāi)封第一講書(shū)人閱讀 162,415評(píng)論 0 353
  • 文/不壞的土叔 我叫張陵独榴,是天一觀的道長(zhǎng)却妨。 經(jīng)常有香客問(wèn)我,道長(zhǎng)括眠,這世上最難降的妖魔是什么彪标? 我笑而不...
    開(kāi)封第一講書(shū)人閱讀 58,157評(píng)論 1 292
  • 正文 為了忘掉前任,我火速辦了婚禮掷豺,結(jié)果婚禮上捞烟,老公的妹妹穿的比我還像新娘。我一直安慰自己当船,他們只是感情好题画,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,171評(píng)論 6 388
  • 文/花漫 我一把揭開(kāi)白布。 她就那樣靜靜地躺著德频,像睡著了一般苍息。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上壹置,一...
    開(kāi)封第一講書(shū)人閱讀 51,125評(píng)論 1 297
  • 那天竞思,我揣著相機(jī)與錄音,去河邊找鬼钞护。 笑死盖喷,一個(gè)胖子當(dāng)著我的面吹牛,可吹牛的內(nèi)容都是我干的难咕。 我是一名探鬼主播课梳,決...
    沈念sama閱讀 40,028評(píng)論 3 417
  • 文/蒼蘭香墨 我猛地睜開(kāi)眼距辆,長(zhǎng)吁一口氣:“原來(lái)是場(chǎng)噩夢(mèng)啊……” “哼!你這毒婦竟也來(lái)了暮刃?” 一聲冷哼從身側(cè)響起跨算,我...
    開(kāi)封第一講書(shū)人閱讀 38,887評(píng)論 0 274
  • 序言:老撾萬(wàn)榮一對(duì)情侶失蹤,失蹤者是張志新(化名)和其女友劉穎椭懊,沒(méi)想到半個(gè)月后诸蚕,有當(dāng)?shù)厝嗽跇?shù)林里發(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 45,310評(píng)論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡灾搏,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,533評(píng)論 2 332
  • 正文 我和宋清朗相戀三年挫望,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了立润。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片狂窑。...
    茶點(diǎn)故事閱讀 39,690評(píng)論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡,死狀恐怖桑腮,靈堂內(nèi)的尸體忽然破棺而出泉哈,到底是詐尸還是另有隱情,我是刑警寧澤破讨,帶...
    沈念sama閱讀 35,411評(píng)論 5 343
  • 正文 年R本政府宣布丛晦,位于F島的核電站,受9級(jí)特大地震影響提陶,放射性物質(zhì)發(fā)生泄漏烫沙。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,004評(píng)論 3 325
  • 文/蒙蒙 一隙笆、第九天 我趴在偏房一處隱蔽的房頂上張望锌蓄。 院中可真熱鬧,春花似錦撑柔、人聲如沸瘸爽。這莊子的主人今日做“春日...
    開(kāi)封第一講書(shū)人閱讀 31,659評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽(yáng)剪决。三九已至,卻和暖如春檀训,著一層夾襖步出監(jiān)牢的瞬間柑潦,已是汗流浹背。 一陣腳步聲響...
    開(kāi)封第一講書(shū)人閱讀 32,812評(píng)論 1 268
  • 我被黑心中介騙來(lái)泰國(guó)打工峻凫, 沒(méi)想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留妒茬,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 47,693評(píng)論 2 368
  • 正文 我出身青樓蔚晨,卻偏偏與公主長(zhǎng)得像乍钻,于是被迫代替她去往敵國(guó)和親肛循。 傳聞我的和親對(duì)象是個(gè)殘疾皇子,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,577評(píng)論 2 353

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