反射教學(xué):寫出風(fēng)騷的Java代碼的基本功

反射是java語言中的一個(gè)特性焰宣,反射機(jī)制是指在程序的運(yùn)行狀態(tài)中,可以構(gòu)造任意一個(gè)類的對象谭溉,可以了解任意一個(gè)對象所屬的類墙懂,可以了解任意一個(gè)類的成員變量和方法,可以調(diào)用任意一個(gè)對象的屬性和方法扮念。 這種動(dòng)態(tài)獲取程序信息以及動(dòng)態(tài)調(diào)用對象的功能稱為Java語言的反射機(jī)制损搬。 反射被視為動(dòng)態(tài)語言的關(guān)鍵。
以上是java關(guān)于反射的八股文,可能不是很好背巧勤,但是絕大部分java程序員都不會(huì)在實(shí)際開發(fā)中去使用反射嵌灰。
合理使用反射,可以讓代碼再不影響性能的基礎(chǔ)上更加優(yōu)美颅悉,拓展性更加的好沽瞭。
下面從幾個(gè)點(diǎn)來講解反射的使用

反射的一些問題

使用反射一定性能差?

很多程序員可能
都會(huì)以反射性能不好的原因去拒絕使用反射剩瓶。想要合理(風(fēng)騷)的使用反射驹溃,首先需要了解反射為什么性能不好。反射的性能問題總體來說有三點(diǎn)
1.反射調(diào)用過程中會(huì)產(chǎn)生大量的臨時(shí)對象儒搭,這些對象會(huì)消耗內(nèi)存,增加gc頻率芙贫,從而影響性能搂鲫。
2.反射調(diào)用方法時(shí)會(huì)從方法數(shù)組中遍歷查找,并且會(huì)檢查可見性等操作會(huì)耗時(shí)磺平。
3.反射在達(dá)到一定次數(shù)時(shí)魂仍,會(huì)動(dòng)態(tài)編寫字節(jié)碼并加載到內(nèi)存中,這個(gè)字節(jié)碼沒有經(jīng)過編譯器優(yōu)化拣挪,也不能享受JIT優(yōu)化擦酌。

那么如何去優(yōu)化:
1.如果是使用反射去讀取字段,讀取方法菠劝,可以使用一個(gè)公共類在初始化的時(shí)候掃描運(yùn)行過程中可能需要使用的反射的類赊舶,并緩存反射后的一些結(jié)果,如Field,Methord方法赶诊。
2.不在超高并發(fā)的請求鏈路中使用反射中的invoke,field的set,get等操作笼平,因?yàn)椴荒芟硎躂IT優(yōu)化,不過問題不大舔痪,實(shí)際測試寓调,影響其實(shí)很小(只要使用地方不太多锄码,是可以使用的)夺英。

總結(jié)一下就是,只需要合理設(shè)置緩存滋捶,考慮性能問題痛悯,在任何地方使用反射都沒啥大問題,你的編程的思想才是限制你程序性能的最主要的因素重窟。

反射能做什么灸蟆?

1. 獲取當(dāng)前的類的class信息

Class my = this.getClass();
        System.out.println("我是誰"+my.getName());
        System.out.println("我有哪些成員變量"+ Arrays.toString(my.getDeclaredFields()));
        System.out.println("我有哪些成員變量(包含私有,但不包括繼承的)"+ Arrays.toString(my.getDeclaredFields()));
        System.out.println("我有哪些方法"+ Arrays.toString(my.getMethods()));
        System.out.println("我有哪些方法(包含私有,但不包括繼承的方法)"+ Arrays.toString(my.getDeclaredMethods()));
        System.out.println("我有哪些注解(包含繼承)"+ Arrays.toString(my.getAnnotations()));
        System.out.println("我有哪些注解(不包含繼承)"+ Arrays.toString(my.getDeclaredAnnotations()));

這樣一來,就獲取了當(dāng)前類的class對象,并獲得了成員變量炒考,方法可缚,注解一系列的信息。

2.對成員變量進(jìn)行操作

Field fieldOne = this.getClass().getDeclaredField("dateList");
        System.out.println("字段是什么類型斋枢?"+fieldOne.getType());
        //這個(gè)字段是不是Collection接口的實(shí)現(xiàn)類帘靡?
        if (Collection.class.isAssignableFrom(fieldOne.getType())
                && fieldOne.getGenericType() instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) fieldOne.getGenericType();
            Type[] fieldArgTypes = parameterizedType.getActualTypeArguments();
            for (Type fieldArgType : fieldArgTypes) {
                System.out.println("集合類型是什么類型的集合?"+(Class) fieldArgType);
            }
        }
        //給這個(gè)字段賦值瓤帚,注意:類型需要兼容侵蒙,可以是子類
        fieldOne.set(this, Lists.newArrayList("123123","1212"));
        System.out.println("通過反射后設(shè)置進(jìn)去了什么值,通過反射獲取出來看看"+fieldOne.get(this));

通過getType可以直接拿到class飘千,并且通過getGenericType返回的ParameterizedType中的ActualTypeArguments可以獲取到字段類型<T>中的類型class隘世。也可以直接調(diào)用set/get獲取字段的值或者是設(shè)置字段的值

3.對方法進(jìn)行操作

拿到了xxx.class對象的時(shí)候,直接調(diào)用getMethod或者getMethods方法就可以怯邪,可以拿到方法的Method對象绊寻。這里,如果是常用方法悬秉,可以把這個(gè)對象緩存起來澄步。Method最常用的方法是method.invoke(),通過傳入對象本身和方法對應(yīng)的入?yún)⒑兔冢{(diào)用方法村缸。此外,如果是私有方法武氓,可以使用method.setAccessible(true)取消權(quán)限檢查

Method testMethod = my.getMethod("test",String.class,Integer.class);
testMethod.setAccessible(true);
String result = (String)testMethod.invoke(my,"haha", 1);
System.out.println(result);

4.對抽象父類的泛型獲取子類的具體填充類型梯皿。

開發(fā)的時(shí)候有時(shí)候父類形如 XXX<T>的,需要在父類定義一些通用的方法县恕,但是這時(shí)候需要?jiǎng)?chuàng)建一個(gè)T類型的示例索烹,這時(shí)候因?yàn)閖ava擦除的特效,T的屬性是被擦除的弱睦,需要如何去獲得T的類型呢百姓。
利用反射原理,子類的T如果已經(jīng)確定况木,調(diào)用父類的方法垒拢,是可以獲得當(dāng)前this對象的T的class或者是實(shí)例.
關(guān)鍵方法 getActualTypeArguments。這個(gè)方法可以獲得當(dāng)前泛型類型的數(shù)組火惊,作用在實(shí)例對象上求类。

private T createModel() {

        try {
            Type superClass = getClass().getGenericSuperclass();
            //關(guān)鍵代碼,拿到當(dāng)前類<>中的第一個(gè)類型例如<K.V>屹耐,getActualTypeArguments的返回K下標(biāo)為0尸疆,V下標(biāo)為1
            Type type = ((ParameterizedType) superClass).getActualTypeArguments()[0];
            Class<?> clazz = getRawType(type);
            return (T) clazz.newInstance();
        } catch (Exception e) {
            log.error("AbstactYsConfig createModel error",e);
        }
        return null;
    }

    private static Class<?> getRawType(Type type) {
        if (type instanceof Class) {
            return (Class) type;
        } else if (type instanceof ParameterizedType) {
            ParameterizedType parameterizedType = (ParameterizedType) type;
            Type rawType = parameterizedType.getRawType();
            return (Class) rawType;
        } else if (type instanceof GenericArrayType) {
            Type componentType = ((GenericArrayType) type).getGenericComponentType();
            return Array.newInstance(getRawType(componentType), 0).getClass();
        } else if (type instanceof TypeVariable) {
            return Object.class;
        } else if (type instanceof WildcardType) {
            return getRawType(((WildcardType) type).getUpperBounds()[0]);
        } else {
            String className = type == null ? "null" : type.getClass().getName();
            throw new IllegalArgumentException("Expected a Class, ParameterizedType, or GenericArrayType, but <" + type + "> is of type " + className);
        }
    }
最后編輯于
?著作權(quán)歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末,一起剝皮案震驚了整個(gè)濱河市,隨后出現(xiàn)的幾起案子寿弱,更是在濱河造成了極大的恐慌犯眠,老刑警劉巖,帶你破解...
    沈念sama閱讀 216,402評論 6 499
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件症革,死亡現(xiàn)場離奇詭異筐咧,居然都是意外死亡,警方通過查閱死者的電腦和手機(jī)噪矛,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 92,377評論 3 392
  • 文/潘曉璐 我一進(jìn)店門量蕊,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人艇挨,你說我怎么就攤上這事残炮。” “怎么了缩滨?”我有些...
    開封第一講書人閱讀 162,483評論 0 353
  • 文/不壞的土叔 我叫張陵势就,是天一觀的道長。 經(jīng)常有香客問我楷怒,道長蛋勺,這世上最難降的妖魔是什么瓦灶? 我笑而不...
    開封第一講書人閱讀 58,165評論 1 292
  • 正文 為了忘掉前任鸠删,我火速辦了婚禮,結(jié)果婚禮上贼陶,老公的妹妹穿的比我還像新娘刃泡。我一直安慰自己,他們只是感情好碉怔,可當(dāng)我...
    茶點(diǎn)故事閱讀 67,176評論 6 388
  • 文/花漫 我一把揭開白布烘贴。 她就那樣靜靜地躺著,像睡著了一般撮胧。 火紅的嫁衣襯著肌膚如雪桨踪。 梳的紋絲不亂的頭發(fā)上,一...
    開封第一講書人閱讀 51,146評論 1 297
  • 那天芹啥,我揣著相機(jī)與錄音锻离,去河邊找鬼。 笑死墓怀,一個(gè)胖子當(dāng)著我的面吹牛汽纠,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播傀履,決...
    沈念sama閱讀 40,032評論 3 417
  • 文/蒼蘭香墨 我猛地睜開眼虱朵,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側(cè)響起碴犬,我...
    開封第一講書人閱讀 38,896評論 0 274
  • 序言:老撾萬榮一對情侶失蹤絮宁,失蹤者是張志新(化名)和其女友劉穎,沒想到半個(gè)月后翅敌,有當(dāng)?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體羞福,經(jīng)...
    沈念sama閱讀 45,311評論 1 310
  • 正文 獨(dú)居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點(diǎn)故事閱讀 37,536評論 2 332
  • 正文 我和宋清朗相戀三年蚯涮,在試婚紗的時(shí)候發(fā)現(xiàn)自己被綠了治专。 大學(xué)時(shí)的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片。...
    茶點(diǎn)故事閱讀 39,696評論 1 348
  • 序言:一個(gè)原本活蹦亂跳的男人離奇死亡遭顶,死狀恐怖张峰,靈堂內(nèi)的尸體忽然破棺而出,到底是詐尸還是另有隱情棒旗,我是刑警寧澤喘批,帶...
    沈念sama閱讀 35,413評論 5 343
  • 正文 年R本政府宣布,位于F島的核電站铣揉,受9級(jí)特大地震影響饶深,放射性物質(zhì)發(fā)生泄漏。R本人自食惡果不足惜逛拱,卻給世界環(huán)境...
    茶點(diǎn)故事閱讀 41,008評論 3 325
  • 文/蒙蒙 一敌厘、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧朽合,春花似錦俱两、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 31,659評論 0 22
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至讲婚,卻和暖如春尿孔,著一層夾襖步出監(jiān)牢的瞬間,已是汗流浹背筹麸。 一陣腳步聲響...
    開封第一講書人閱讀 32,815評論 1 269
  • 我被黑心中介騙來泰國打工活合, 沒想到剛下飛機(jī)就差點(diǎn)兒被人妖公主榨干…… 1. 我叫王不留,地道東北人竹捉。 一個(gè)月前我還...
    沈念sama閱讀 47,698評論 2 368
  • 正文 我出身青樓芜辕,卻偏偏與公主長得像,于是被迫代替她去往敵國和親块差。 傳聞我的和親對象是個(gè)殘疾皇子侵续,可洞房花燭夜當(dāng)晚...
    茶點(diǎn)故事閱讀 44,592評論 2 353

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