免费视频淫片aa毛片_日韩高清在线亚洲专区vr_日韩大片免费观看视频播放_亚洲欧美国产精品完整版

打開(kāi)APP
userphoto
未登錄

開(kāi)通VIP,暢享免費(fèi)電子書等14項(xiàng)超值服

開(kāi)通VIP
反射、注解與依賴注入總結(jié)

上一篇【線程、多線程與線程池總結(jié)】中主要記錄線程、多線程相關(guān)概念,側(cè)重于線程的Future使用與線程池的操作;同樣這一篇【反射、注解與依賴注入總結(jié)】依然著重于相關(guān)概念與使用。

現(xiàn)在在我們構(gòu)建自己或公司的項(xiàng)目中,或多或少都會(huì)依賴幾個(gè)流行比較屌的第三方庫(kù),比如:Butter KnifeRetrofit、Dagger 2等,如果你沒(méi)用過(guò),那你需要找時(shí)間補(bǔ)一下啦;有時(shí)在使用后我們會(huì)好奇他們到底是怎么做到這種簡(jiǎn)潔、高效、松耦合等諸多優(yōu)點(diǎn)的,當(dāng)然這里我不探討它們具體怎么實(shí)現(xiàn)的,而關(guān)心的是它們都用到同樣的技術(shù)反射和注解,并實(shí)現(xiàn)的依賴注入。

如果你好奇這些庫(kù)具體是怎么實(shí)現(xiàn)的,或者想了解他們實(shí)現(xiàn)的原理,這里向你推薦幾篇文章:
1、android注解Butterknife的使用及代碼分析
2、Retrofit源碼1: 為什么寫一個(gè)interface就可以實(shí)現(xiàn)http請(qǐng)求
3、Retrofit分析-漂亮的解耦套路
4、Dagger 源碼解析
5、Android:dagger2讓你愛(ài)不釋手-基礎(chǔ)依賴注入框架篇
6、Android:dagger2讓你愛(ài)不釋手-重點(diǎn)概念講解、融合篇
7、Android:dagger2讓你愛(ài)不釋手-終結(jié)篇

這些好文章已經(jīng)幫你收藏了,下面直接進(jìn)入我的主題【反射、注解與依賴注入總結(jié)】。

● 反射(Reflection)

反射的概念

主要是指程序可以訪問(wèn),檢測(cè)和修改它本身狀態(tài)或行為的一種能力,并能根據(jù)自身行為的狀態(tài)和結(jié)果,調(diào)整或修改應(yīng)用所描述行為的狀態(tài)和相關(guān)的語(yǔ)義。

概念看著就有些暈或不知所云啦,可以通過(guò)反射的作用理解它的概念。

反射的作用

反射可以讓我們?cè)谶\(yùn)行時(shí)獲取類的屬性,方法,構(gòu)造方法、父類、接口等信息,通過(guò)反射還可以讓我們?cè)谶\(yùn)行期實(shí)例化對(duì)象、調(diào)用方法、即使方法或?qū)傩允撬接械牡囊部梢酝ㄟ^(guò)反射的形式調(diào)用。

所有為什么第三方庫(kù)基本都會(huì)使用到反射,正是因?yàn)榉瓷溥@種 “看透 Class” 的能力。

反射相關(guān)的類、方法

要看透一個(gè)類,首先要獲取這個(gè)類的對(duì)象,其它信息都是通過(guò)這個(gè)對(duì)象獲取的,下面的所有的示例具體操作代碼請(qǐng)參考 【個(gè)人學(xué)習(xí)項(xiàng)目DroidStudy】,我在這個(gè)工程下新建一個(gè) ReflectionActivity,包的路徑為 com.sun.study.ui.activity.ReflectionActivity,通過(guò)反射相關(guān)的類、方法讓我看透這個(gè)類。

1、獲取對(duì)象的三種方式:

第一種、知道一個(gè)類,直接獲取 Class 對(duì)象

Class<?> cls1 = ReflectionActivity.class;

第二種、如果已經(jīng)得到了某個(gè)對(duì)象,可以通過(guò)這個(gè)對(duì)象獲取 Class 對(duì)象

ReflectionActivity activity = new ReflectionActivity();Class<?> cls2 = activity.getClass();

第三種、如果你在編譯期獲取不到目標(biāo)類型,但是你知道它的完整類路徑,那么你可以通過(guò)如下的形式來(lái)獲取 Class 對(duì)象,這樣獲取可能會(huì)拋出異常 ClassNotFoundException。

try {    Class<?> cls3 = Class.forName("com.sun.study.ui.activity.ReflectionActivity");} catch (ClassNotFoundException e) {    e.printStackTrace();}

2、反射的相關(guān)方法和示例

列出反射的相關(guān)方法

getName():獲得類的完整名字。  newInstance():通過(guò)類的不帶參數(shù)的構(gòu)造方法創(chuàng)建這個(gè)類的一個(gè)對(duì)象。getFields():獲得類的public類型的屬性。  getDeclaredFields():獲得類的所有屬性。getMethods():獲得類的public類型的方法。  getDeclaredMethods():獲得類的所有方法。  getMethod(String name, Class[] parameterTypes):獲得類的特定方法。getModifiers()和Modifier.toString():獲得屬修飾符,例如private,public,static等  getReturnType():獲得方法的返回類型  getParameterTypes():獲得方法的參數(shù)類型getConstructors():獲得類的public類型的構(gòu)造方法。  getConstructor(Class[] parameterTypes):獲得類的特定構(gòu)造方法。getSuperclass():獲取某類的父類  getInterfaces():獲取某類實(shí)現(xiàn)的接口

示例一:獲得類的所有方法(Method)信息

private void getMethodsInfo() {    Class<ReflectionActivity> cls = ReflectionActivity.class;    Method[] methods = cls.getDeclaredMethods();    if (methods == null) return;    StringBuilder sb = new StringBuilder();    for (Method method:methods) {        sb.append(Modifier.toString(method.getModifiers())).append(" ");        sb.append(method.getReturnType()).append(" ");        sb.append(method.getName()).append("(");        Class[] parameters = method.getParameterTypes();        if (parameters != null) {            for (int i=0; i<parameters.length; i++) {                Class paramCls = parameters[i];                sb.append(paramCls.getSimpleName());                if (i < parameters.length - 1) sb.append(", ");            }        }        sb.append(")\n\n");    }    tvInfo.setText(sb.toString());}

運(yùn)行結(jié)果如下圖:

reflection_icon1.png

示例一:獲得類的所有屬性(Field)信息,并修改類型Int屬性i的值

private void modifyFieldValue() {    Class<ReflectionActivity> cls = ReflectionActivity.class;    Field[] fields = cls.getDeclaredFields();    if (fields == null) return;    StringBuilder sb = new StringBuilder();    sb.append("獲得類的所有屬性信息:\n\n");    for (Field field:fields) {        sb.append(Modifier.toString(field.getModifiers())).append(" ");        sb.append(field.getType().getSimpleName()).append(" ");        sb.append(field.getName()).append(";");        sb.append("\n\n");    }    try {        sb.append("屬性i的默認(rèn)值:i = ");        Field f = cls.getDeclaredField("i");        sb.append(f.getInt("i")).append("\n\n");        f.set("i", 100);        sb.append("屬性i修改后的值:i = ");        sb.append(f.getInt("i")).append("\n\n");    } catch (Exception e) {        e.printStackTrace();    }    tvInfo.setText(sb.toString());    toolbar.setSubtitle("修改類型Int屬性i的值");}

運(yùn)行結(jié)果如下圖:

reflection_icon2.png

更多示例請(qǐng)參考 【個(gè)人學(xué)習(xí)項(xiàng)目DroidStudy】

反射的相關(guān)內(nèi)容先記錄到這,接下來(lái)看看注解相關(guān)概念與使用。

● 注解(Annotation)

注解的概念

注解(Annotation),也叫元數(shù)據(jù)。一種代碼級(jí)別的說(shuō)明。它是JDK 1.5及以后版本引入的一個(gè)特性,與類、接口、枚舉是在同一個(gè)層次。它可以聲明在包、類、字段、方法、局部變量、方法參數(shù)等的前面,用來(lái)對(duì)這些元素進(jìn)行說(shuō)明,注釋。

注解的作用

1、標(biāo)記作用,用于告訴編譯器一些信息讓編譯器能夠?qū)崿F(xiàn)基本的編譯檢查,如@Override、Deprecated,看下它倆的源碼

@Target(ElementType.METHOD)@Retention(RetentionPolicy.SOURCE)public @interface Override {}@Documented@Retention(RetentionPolicy.RUNTIME)public @interface Deprecated {}

2、編譯時(shí)動(dòng)態(tài)處理,動(dòng)態(tài)生成代碼,如Butter KnifeDagger 2

3、運(yùn)行時(shí)動(dòng)態(tài)處理,獲得注解信息,如Retrofit

注解的分類

注解的分類有兩種分法:

第一種分法

1、基本內(nèi)置注解,是指Java自帶的幾個(gè)Annotation,如@Override、Deprecated、@SuppressWarnings等

2、元注解(meta-annotation),是指負(fù)責(zé)注解其他注解的注解,JDK 1.5及以后版本定義了4個(gè)標(biāo)準(zhǔn)的元注解類型,如下:

1、@Target2、@Retention3、@Documented4、@Inherited

3、自定義注解,根據(jù)需要可以自定義注解,自定義注解需要用到上面的meta-annotation

第二種分法,根據(jù)作用域分類

1、源碼時(shí)注解(RetentionPolicy.SOURCE)
2、編譯時(shí)注解(RetentionPolicy.CLASS)
3、運(yùn)行時(shí)注解(RetentionPolicy.RUNTIME)

注解相關(guān)知識(shí)點(diǎn)

1、元注解相關(guān)信息

@Target:指Annotation所修飾的對(duì)象范圍,通過(guò)ElementType取值有8種,如下

TYPE:類、接口(包括注解類型)或枚舉FIELD:屬性METHOD:方法PARAMETER:參數(shù)CONSTRUCTOR:構(gòu)造函數(shù)LOCAL_VARIABLE:局部變量ANNOTATION_TYPE:注解類型PACKAGE:包

@Retention:指Annotation被保留的時(shí)間長(zhǎng)短,通過(guò)RetentionPolicy取值有3種,如下:

SOURCE:在源文件中有效(即源文件保留)  CLASS:在class文件中有效(即class保留)  RUNTIME:在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留)

@Documented:是一個(gè)標(biāo)記注解,用于描述其它類型的注解應(yīng)該被作為被標(biāo)注的程序成員的公共API,因此可以被例如javadoc此類的工具文檔化。

@Inherited:也是一個(gè)標(biāo)記注解,@Inherited闡述了某個(gè)被標(biāo)注的類型是被繼承的

2、注解定義格式

public @interface 注解名 { 定義體 }

3、注解參數(shù)可支持的數(shù)據(jù)類型:

8種基本數(shù)據(jù)類型 int、float、boolean、byte、double、char、long、short  String、Class、enum、Annotation  以上所有類型的數(shù)組

4、?注意:自定義注解如果只有一個(gè)參數(shù)成員,最好把定義體參數(shù)名稱設(shè)為"value",如@Target

@Documented@Retention(RetentionPolicy.RUNTIME)@Target(ElementType.ANNOTATION_TYPE)public @interface Target {    ElementType[] value();}

看一個(gè)示例

具體要求和運(yùn)行結(jié)果都在下面這張圖上顯示出來(lái)了,貼下圖

annotation_icon.png

再貼三塊代碼,首先是自定義注解代碼:

@Target(ElementType.METHOD)@Retention(RetentionPolicy.RUNTIME)@Inherited@Documentedpublic @interface RequestAnnotation {    boolean withDialog() default true;    String withMessage() default "正在加載,請(qǐng)稍后...";}

其次是執(zhí)行模擬的網(wǎng)絡(luò)請(qǐng)求,核心代碼是通過(guò)上面的反射和注解完成的;具體詳細(xì)代碼請(qǐng)參考 【個(gè)人學(xué)習(xí)項(xiàng)目DroidStudy】,下次使用動(dòng)態(tài)代理和Google的dexmaker完成這個(gè)功能,敬請(qǐng)關(guān)注,如果你對(duì)線程池還不清晰請(qǐng)參考我以前的文章【線程、多線程與線程池總結(jié)】。貼下核心代碼:

// 線程池private static ExecutorService pool = Executors.newCachedThreadPool();// 模擬處理網(wǎng)絡(luò)請(qǐng)求public boolean process(final Class<?> clazz, String methodName, final Object... args) throws Exception {    Class[] argsClass = getClazzByArgs(args);    final Method method = clazz.getDeclaredMethod(methodName, argsClass);    if (method == null) {        sendMsg(TYPE_ERROR);        return false;    }    // 獲取注解信息    RequestAnnotation annotation = method.getAnnotation(RequestAnnotation.class);    if (annotation != null && annotation.withDialog()) {        loadingDialog.show(annotation.withMessage());    }    pool.execute(new Runnable() {        @Override        public void run() {            try {                method.setAccessible(true);                method.invoke(clazz.newInstance(), args);                sendMsg(TYPE_SUCCESS);            } catch (Exception e) {                e.printStackTrace();            }        }    });    return true;}

最后是調(diào)用網(wǎng)絡(luò)請(qǐng)求接口:

@RequestAnnotation(withDialog = false, withMessage = "正在加載,請(qǐng)稍后...")public void apiTestFunc(String param1, String param2) {    try {        // 模擬網(wǎng)絡(luò)請(qǐng)求的耗時(shí)操作        Thread.sleep(3000);    } catch (InterruptedException e) {        e.printStackTrace();    }}// 點(diǎn)擊執(zhí)行的代碼DynamicProxyUtil proxyUtil = new DynamicProxyUtil(AnnotationActivity.this);proxyUtil.process(RequestNetworkApi.class, "apiTestFunc", "參數(shù)一", "參數(shù)二");

● 依賴注入(Dependency Injection)

依賴注入(Dependency Injection):可以通過(guò)這個(gè)服務(wù)來(lái)安全的注入組件到應(yīng)用程序中,在應(yīng)用程序部署的時(shí)候還可以選擇從特定的接口屬性進(jìn)行注入。

看完上面反射和注解的記錄后,可以更好的理解依賴注入,如果你不用那些第三方的注入庫(kù)你也在經(jīng)常用到依賴注入,比如下面這一段從codekk上截取的代碼:

public class Human {    ...    Father father;    ...    public Human(Father father) {        this.father = father;    }}

上面代碼中,我們將 father 對(duì)象作為構(gòu)造函數(shù)的一個(gè)參數(shù)傳入。在調(diào)用 Human 的構(gòu)造方法之前外部就已經(jīng)初始化好了 Father 對(duì)象。像這種非自己主動(dòng)初始化依賴,而通過(guò)外部來(lái)傳入依賴的方式,我們就稱為依賴注入。

依賴注入的實(shí)現(xiàn)有多種途徑,而在 Java 中,使用注解是最常用的。比如通過(guò)Butter Knife、Dagger依賴注入庫(kù)實(shí)現(xiàn),都是使用注解來(lái)實(shí)現(xiàn)依賴注入,但它利用 APT(Annotation Process Tool) 在編譯時(shí)生成輔助類,這些類繼承特定父類或?qū)崿F(xiàn)特定接口,程序在運(yùn)行時(shí)加載這些輔助類,調(diào)用相應(yīng)接口完成依賴生成和注入。

依賴注入在這里僅僅剖析下概念,有時(shí)間將會(huì)補(bǔ)一個(gè)例子,暫且到這吧。


文/孫福生(簡(jiǎn)書作者)
原文鏈接:http://www.jianshu.com/p/24820bf3df5c
  

本站僅提供存儲(chǔ)服務(wù),所有內(nèi)容均由用戶發(fā)布,如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請(qǐng)點(diǎn)擊舉報(bào)。
打開(kāi)APP,閱讀全文并永久保存 查看更多類似文章
猜你喜歡
類似文章
秒懂,Java 注解 (Annotation)你可以這樣學(xué)
張龍 Annotation學(xué)習(xí)筆記
java注解應(yīng)用實(shí)例
深入理解spring中的各種注解
Java自定義注解
[直呼內(nèi)行] 注解開(kāi)發(fā)才是簡(jiǎn)潔之道,讓同行直呼內(nèi)行的Java注解技術(shù)
更多類似文章 >>
生活服務(wù)
分享 收藏 導(dǎo)長(zhǎng)圖 關(guān)注 下載文章
綁定賬號(hào)成功
后續(xù)可登錄賬號(hào)暢享VIP特權(quán)!
如果VIP功能使用有故障,
可點(diǎn)擊這里聯(lián)系客服!

聯(lián)系客服