java基礎(chǔ)(反射)

在學(xué)習(xí)Java的過程中坛吁,很多框架的原理都會(huì)涉及到反射知識(shí)摩幔,如果你對(duì)反射不太了解甚至都沒看過彤委,那么你的提升會(huì)有點(diǎn)慢。在面試當(dāng)中热鞍,你說你會(huì)用一個(gè)框架葫慎,并不能體現(xiàn)出你的什么能力,但是你說你會(huì)用而且還能分析框架的原理薇宠,還有能力舉一反三自己造個(gè)輪子偷办。那么面試官就會(huì)對(duì)你刮目想看了。當(dāng)然學(xué)習(xí)的過程是漫長(zhǎng)的澄港,一口也吃不成一個(gè)胖子椒涯,帶著自己心里的那個(gè)夢(mèng)想堅(jiān)持下去。

概念

定義

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語言的反射機(jī)制。

作用

  1. 在運(yùn)行時(shí)判斷任意一個(gè)對(duì)象所屬的類详囤。

  2. 在運(yùn)行時(shí)構(gòu)造任意一個(gè)類的對(duì)象财骨。

  3. 在運(yùn)行時(shí)判斷任意一個(gè)類所具有的成員變量和方法。

  4. 在運(yùn)行時(shí)調(diào)用任意一個(gè)對(duì)象的方法藏姐。

  5. 生成動(dòng)態(tài)代理隆箩。

應(yīng)用場(chǎng)景

  1. 逆向代碼 ,例如反編譯

  2. 與注解相結(jié)合的框架 例如Retrofit

  3. 單純的反射機(jī)制應(yīng)用框架 例如EventBus

  4. 動(dòng)態(tài)生成類框架 例如Gson

反射的簡(jiǎn)單使用

我這先寫一個(gè)User類方便后面的講解

public class User {
    private String name;
    private int age;
    public String sex;

    public User() {
    }

    public User(String name) {
        this.name = name;
    }

    public User(String name, int age) {
        this.name = name;
        this.age = age;
    }

    public User(String name, Integer age, String sex) {
        this.name = name;
        this.age = age;
        this.sex = sex;
    }


    public String getName() {
        return name;
    }

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

    public int getAge() {
        return age;
    }

    public void setAge(int age) {
        this.age = age;
    }

    public String getSex() {
        return sex;
    }

    public void setSex(String sex) {
        this.sex = sex;
    }

    /**
     * 測(cè)試方法
     * @param msg
     * @return
     */
    public String textMethed(String msg) {
        return msg;
    }
}

拿到Class對(duì)象

每個(gè)類被加載之后羔杨,系統(tǒng)就會(huì)為該類生成一個(gè)對(duì)應(yīng)的Class對(duì)象捌臊。通過該Class對(duì)象就可以訪問到JVM中的這個(gè)類。

獲取Class對(duì)象有如下三種方式:

  1. 使用Class類的forName(String clazzName)靜態(tài)方法兜材。該方法需要傳入字符串參數(shù)理澎,該字符串參數(shù)的值是某個(gè)類的全限定名(必須添加完整包名)逞力。

  2. 調(diào)用某個(gè)類的class屬性來獲取該類對(duì)應(yīng)的Class對(duì)象。

  3. 調(diào)用某個(gè)對(duì)象的getClass()方法糠爬。該方法是java.lang.Object類中的一個(gè)方法掏击。

 public static  void getClas(){
        Class uClass;
        //三種獲取class對(duì)象的方式
        try {
            uClass = Class.forName("com.zhong.reflect.User");//1
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
        uClass = User.class;//2
        uClass = new User().getClass();//3
    }

我們拿到了這個(gè)類的class對(duì)象那么我們能對(duì)這個(gè)類做些什么操作呢?

反射查看信息

獲取對(duì)象中的成員屬性

 public void getField(Class uClass) {
        Field[] allFields = uClass.getDeclaredFields();//獲取class對(duì)象的所有屬性
        Field[] publicFields = uClass.getFields();//獲取class對(duì)象的public屬性
        try {
            Field ageField = uClass.getDeclaredField("age");//獲取class指定屬性
            Field desField = uClass.getField("sex");//獲取class指定的public屬性 
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }

    }

獲取對(duì)象中的成員方法

    public static void getMethed(Class uClass) {
        Method[] methods = uClass.getDeclaredMethods();//獲取class對(duì)象的所有聲明方法
        Method[] allMethods = uClass.getMethods();//獲取class對(duì)象的所有public方法 包括父類的方法
        try {
            Method method = uClass.getMethod("textMethed", String.class);//返回次Class對(duì)象對(duì)應(yīng)類的秩铆、帶指定形參列表的public方法
            Method declaredMethod = uClass.getDeclaredMethod("textMethed", String.class);//返回次Class對(duì)象對(duì)應(yīng)類的砚亭、帶指定形參列表的方法
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

獲取對(duì)象中的構(gòu)造方法

 public static void getConstructor(Class uClass) {
        Constructor<?>[] allConstructors = uClass.getDeclaredConstructors();//獲取class對(duì)象的所有聲明構(gòu)造函數(shù)
        Constructor<?>[] publicConstructors = uClass.getConstructors();//獲取class對(duì)象public構(gòu)造函數(shù)
        try {
            Constructor<?> constructor = uClass.getDeclaredConstructor(String.class);//獲取指定聲明構(gòu)造函數(shù)
            Constructor publicConstructor = uClass.getConstructor(String.class);//獲取指定聲明的public構(gòu)造函數(shù)
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

    }

獲取對(duì)象的class對(duì)象的信息

boolean isPrimitive = uClass.isPrimitive();//判斷是否是基礎(chǔ)類型
boolean isArray = uClass.isArray();//判斷是否是集合類
boolean isAnnotation = uClass.isAnnotation();//判斷是否是注解類
boolean isInterface = uClass.isInterface();//判斷是否是接口類
boolean isEnum = uClass.isEnum();//判斷是否是枚舉類
boolean isAnonymousClass=uClass.isAnonymousClass();//判斷是否是匿名內(nèi)部類
boolean isAnnotationPresent=uClass.isAnnotationPresent(Deprecated.class);//判斷是否被某個(gè)注解類修飾
String className = uClass.getName();//獲取class名字 包含包名路徑
Package aPackage = uClass.getPackage();//獲取class的包信息
String simpleName = uClass.getSimpleName();//獲取class類名
int modifiers = uClass.getModifiers();//獲取class訪問權(quán)限
Class<?>[] declaredClasses = uClass.getDeclaredClasses();//內(nèi)部類
Class<?> declaringClass = uClass.getDeclaringClass();//外部類

反射操作對(duì)象

創(chuàng)建對(duì)象

  1. 使用Class對(duì)象的newInstance()方法來創(chuàng)建該Class對(duì)象對(duì)應(yīng)類的實(shí)例。這種方式要求該Class對(duì)象的對(duì)應(yīng)類有默認(rèn)構(gòu)造器殴玛,而執(zhí)行newInstance()方法時(shí)實(shí)際上是利用默認(rèn)構(gòu)造器來創(chuàng)建該類的實(shí)例捅膘。

  2. 先使用Class對(duì)象獲取指定的Constructor對(duì)象,再調(diào)用Constructor對(duì)象的newInstance()方法來創(chuàng)建該Class對(duì)象對(duì)應(yīng)類的實(shí)例滚粟。通過這種方式可以選擇使用指定的構(gòu)造器來創(chuàng)建實(shí)例寻仗。

public static void newIns() throws Exception {
    Class uClass = Class.forName("com.zhong.reflect.User");
    //第一種方式 Class對(duì)象調(diào)用newInstance()方法生成
    User user = (User) uClass.newInstance();
    //第二種方式 對(duì)象獲得對(duì)應(yīng)的Constructor對(duì)象,再通過該Constructor對(duì)象的newInstance()方法生成
    Constructor<?> constructor =uClass.getDeclaredConstructor(String.class, Integer.class,String.class);//獲取指定聲明構(gòu)造函數(shù)
    user = (User) constructor.newInstance("小米", 20, "男");
}

調(diào)用方法

上面我們演示了如何獲取對(duì)象中方法凡壤,現(xiàn)在我們需要調(diào)用這個(gè)方法

public static void invokeMethed() throws Exception {
    Class uClass = Class.forName("com.zhong.reflect.User");
    //創(chuàng)建一個(gè)空對(duì)象
    Object obj = uClass.newInstance();
    //獲取指定參數(shù)的指定方法
    Method textMethed = uClass.getMethod("textMethed", String.class);
    //調(diào)用方法
    Object str = textMethed.invoke(obj, "小米");
    System.out.println(str);
}

注意:

當(dāng)通過Method的invoke()方法來調(diào)用對(duì)應(yīng)的方法時(shí)署尤,Java會(huì)要求程序必須有調(diào)用該方法的權(quán)限。如果程序確實(shí)需要調(diào)用某個(gè)對(duì)象的private方法亚侠,則可以先調(diào)用Method對(duì)象的setAccessible(boolean flag)方法曹体。

setAccessible(boolean flag)

將Method對(duì)象的acessible設(shè)置為指定的布爾值。值為true硝烂,指示該Method在使用時(shí)應(yīng)該取消Java語言的訪問權(quán)限檢查箕别;值為false,則知識(shí)該Method在使用時(shí)要實(shí)施Java語言的訪問權(quán)限檢查滞谢。

訪問成員變量值

public static void changeField() throws Exception{
        Class uClass = Class.forName("com.zhong.reflect.User");
        Object obj = uClass.newInstance();
        //獲取一個(gè)私有屬性
        Field field = uClass.getDeclaredField("age");
        //設(shè)置權(quán)限
        field.setAccessible(true);
        field.setInt(obj,10);
        int age = field.getInt(obj);
        System.out.println(age);
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請(qǐng)聯(lián)系作者
  • 序言:七十年代末串稀,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子狮杨,更是在濱河造成了極大的恐慌母截,老刑警劉巖,帶你破解...
    沈念sama閱讀 218,682評(píng)論 6 507
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件橄教,死亡現(xiàn)場(chǎng)離奇詭異清寇,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)颤陶,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 93,277評(píng)論 3 395
  • 文/潘曉璐 我一進(jìn)店門颗管,熙熙樓的掌柜王于貴愁眉苦臉地迎上來陷遮,“玉大人滓走,你說我怎么就攤上這事∶辈觯” “怎么了搅方?”我有些...
    開封第一講書人閱讀 165,083評(píng)論 0 355
  • 文/不壞的土叔 我叫張陵比吭,是天一觀的道長(zhǎng)。 經(jīng)常有香客問我姨涡,道長(zhǎng)衩藤,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 58,763評(píng)論 1 295
  • 正文 為了忘掉前任涛漂,我火速辦了婚禮赏表,結(jié)果婚禮上,老公的妹妹穿的比我還像新娘匈仗。我一直安慰自己瓢剿,他們只是感情好,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,785評(píng)論 6 392
  • 文/花漫 我一把揭開白布悠轩。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪雪位。 梳的紋絲不亂的頭發(fā)上滞欠,一...
    開封第一講書人閱讀 51,624評(píng)論 1 305
  • 那天,我揣著相機(jī)與錄音何鸡,去河邊找鬼纺弊。 笑死,一個(gè)胖子當(dāng)著我的面吹牛骡男,可吹牛的內(nèi)容都是我干的俭尖。 我是一名探鬼主播,決...
    沈念sama閱讀 40,358評(píng)論 3 418
  • 文/蒼蘭香墨 我猛地睜開眼洞翩,長(zhǎng)吁一口氣:“原來是場(chǎng)噩夢(mèng)啊……” “哼稽犁!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起骚亿,我...
    開封第一講書人閱讀 39,261評(píng)論 0 276
  • 序言:老撾萬榮一對(duì)情侶失蹤已亥,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后来屠,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體虑椎,經(jīng)...
    沈念sama閱讀 45,722評(píng)論 1 315
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長(zhǎng)有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,900評(píng)論 3 336
  • 正文 我和宋清朗相戀三年俱笛,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了捆姜。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 40,030評(píng)論 1 350
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡迎膜,死狀恐怖泥技,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情磕仅,我是刑警寧澤珊豹,帶...
    沈念sama閱讀 35,737評(píng)論 5 346
  • 正文 年R本政府宣布簸呈,位于F島的核電站,受9級(jí)特大地震影響店茶,放射性物質(zhì)發(fā)生泄漏蜕便。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,360評(píng)論 3 330
  • 文/蒙蒙 一贩幻、第九天 我趴在偏房一處隱蔽的房頂上張望轿腺。 院中可真熱鬧,春花似錦丛楚、人聲如沸吃溅。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,941評(píng)論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽决侈。三九已至,卻和暖如春喧务,著一層夾襖步出監(jiān)牢的瞬間赖歌,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 33,057評(píng)論 1 270
  • 我被黑心中介騙來泰國(guó)打工功茴, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留庐冯,地道東北人。 一個(gè)月前我還...
    沈念sama閱讀 48,237評(píng)論 3 371
  • 正文 我出身青樓坎穿,卻偏偏與公主長(zhǎng)得像展父,于是被迫代替她去往敵國(guó)和親。 傳聞我的和親對(duì)象是個(gè)殘疾皇子玲昧,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,976評(píng)論 2 355

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