如何編寫自定義注解

上一篇java注解初探介紹了注解的基本概念, @Retention注解參數(shù)為CLASS時是編譯時注解而RUNTIME時是運行時注解牙捉,這些在上一篇都有介紹,本篇文章將通過Demo來說說編譯時注解和運行時注解橙喘。

1航唆、 運行時注解

運行時注解是通過反射在程序運行時獲取注解信息财异,然后利用信息進行其他處理阱冶。下面是運行時注解的一個簡單Damo寓搬,包含Company、EmployeeName双揪、EmployeeSex注解定義以及EmployeeInfoUtil注解處理器,客戶端包含EmployeeInfo類(成員變量使用注解)和一個main方法包帚。

Compay代碼:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Company {
    public int id() default -1;
    public String name() default "";
    public String address() default "";
}

EmployeeName代碼:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EmployeeName {
    String value () default "";
}

EmployeeSex代碼:

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface EmployeeSex {
    enum Sex{Man,Woman}//定義性別枚舉
    Sex employeeSex()  default Sex.Man;
}

上一篇文章我們也介紹了渔期,注解的關鍵是注解處理器,下面的注解處理器僅僅獲取注解信息

public class EmployeeInfoUtil {
    public static Map getEmployeeInfo(Class<?> clazz){
        HashMap<String ,String> info = new HashMap<>();
        Field[] fields = clazz.getDeclaredFields();//獲取類成員變量
        for (Field field: fields) {//遍歷
            if (field.isAnnotationPresent(EmployeeName.class)){//判斷是不是EmployeeName類型注解
                EmployeeName employeeName = field.getAnnotation(EmployeeName.class);
                info.put("employeeName",employeeName.value());//獲取注解的值
            }
            if (field.isAnnotationPresent(EmployeeSex.class)) {
                EmployeeSex employeeSex = field.getAnnotation(EmployeeSex.class);
                info.put("employeeSex",employeeSex.employeeSex().toString());
            }
            if (field.isAnnotationPresent(Company.class)) {
                Company company = field.getAnnotation(Company.class);
                info.put("company",company.id()+":"+company.name()+":"+company.address());
            }
        }
        return info;
    }
}

EmployeeInfo代碼:

public class EmployeeInfo {
    @EmployeeName("zfq")
    private String employeeName;
    @EmployeeSex(employeeSex = EmployeeSex.Sex.Woman)
    private String employeeSex;
    @Company(id = 1,name = "HYR集團",address = "河南開封")
    private String company;
//省略set和get方法
}

客戶端代碼:

public class EmployeeRun {
    public static void main(String[] args) {
        Map fruitInfo = EmployeeInfoUtil.getEmployeeInfo(EmployeeInfo.class);
        System.out.println(fruitInfo);
    }
}

運行結(jié)果:

{employeeName=zfq, employeeSex=Woman, company=1:HYR集團:河南開封}

2渴邦、編譯時注解

編譯時注解是在程序編譯的時候動態(tài)的生成一些類或者文件疯趟,所以編譯時注解不會影響程序運行時的性能,而運行時注解則依賴于反射谋梭,反射肯定會影響程序運行時的性能信峻,所以一些知名的三方庫一般都是使用編譯時時注解,比如大名鼎鼎的ButterKnife瓮床、Dagger盹舞、Afinal等。下面編譯時注解是編譯時打印使用指定注解的方法的方法信息隘庄,注解的定義和運行時注解一樣踢步,主要是注解處理器對注解的處理不同 。首先AS的工程中新加Module丑掺,選擇java Library(指定library name)获印。

@InjectPrint注解代碼:

@Target({ElementType.FIELD, ElementType.TYPE, ElementType.METHOD})
@Retention(RetentionPolicy.CLASS)
public @interface InjectPrint {
    String value();
}

InjectPrintProcessor處理器代碼:

@SupportedAnnotationTypes("com.example.InjectPrint")//參數(shù)是指定注解類型的全路徑
public class InjectPrintProcessor extends AbstractProcessor {
    @Override
    public boolean process(Set<? extends TypeElement> set, RoundEnvironment roundEnvironment) {
        //獲取InjectPrint類型注解,然后遍歷
        for(Element element : roundEnvironment.getElementsAnnotatedWith(InjectPrint.class)){
            //元素類型是一個方法
            if(element.getKind() == ElementKind.METHOD){
                //強轉(zhuǎn)成方法對應的element街州,同
                // 理兼丰,如果你的注解是一個類,那你可以強轉(zhuǎn)成TypeElement
                ExecutableElement executableElement = (ExecutableElement)element;
                //打印方法名
                System.out.println(executableElement.getSimpleName());
                //打印方法的返回類型
                System.out.println(executableElement.getReturnType().toString());
                //獲取方法所有的參數(shù)
                List<? extends VariableElement> params = executableElement.getParameters();
                for(VariableElement variableElement : params){//遍歷并打印參數(shù)名
                    System.out.println(variableElement.getSimpleName());
                }
                //打印注解的值
                System.out.println("AnnotationValue:"+executableElement.getAnnotation(InjectPrint.class).value());
            }
        }
        return false;
    }
    @Override
    public SourceVersion getSupportedSourceVersion() {
        return SourceVersion.latestSupported();
    }
}

為了我們的AbstractProcessor內(nèi)被使用唆缴,需要在META-INF中顯示標識鳍征,在resources資源文件夾下新建 META-INF/services/javax.annotation.processing.Processor,其內(nèi)容:

 com.example.InjectPrintProcessor //注解處理器的全路徑

具體的目錄結(jié)構如下圖所示:

image

到此我們就可以build整個工程(要把我們的myanno模塊添加到主工程下一起編譯,build->Edit Libraries and Dependencies->主工程module->Dependencies->+->Module dependency)生成jar包了面徽,如下圖

image

我們可以把myanno.jar拷貝出來蟆技,添加到主工程的libs文件夾里,別忘Add As Library
然后,我們就可以在我們的主工程里使用@InjectPrint注解了

image

Build我們的項目质礼,然后Gradle Console控制臺就可以看到輸出信息了

image

注意:如果你編譯過一次下次可能在build的時候可能就看不到控制臺輸出旺聚,這時候你要選擇Rebuild Project

自定義運行時和編譯時注解到這里就介紹完了,如果感興趣的同學可以自己寫寫感受一下眶蕉,下一篇博客我會去研究一下ButterKnife源碼砰粹,繼續(xù)學習。

最后編輯于
?著作權歸作者所有,轉(zhuǎn)載或內(nèi)容合作請聯(lián)系作者
  • 序言:七十年代末造挽,一起剝皮案震驚了整個濱河市碱璃,隨后出現(xiàn)的幾起案子,更是在濱河造成了極大的恐慌饭入,老刑警劉巖嵌器,帶你破解...
    沈念sama閱讀 206,378評論 6 481
  • 序言:濱河連續(xù)發(fā)生了三起死亡事件,死亡現(xiàn)場離奇詭異谐丢,居然都是意外死亡爽航,警方通過查閱死者的電腦和手機,發(fā)現(xiàn)死者居然都...
    沈念sama閱讀 88,356評論 2 382
  • 文/潘曉璐 我一進店門乾忱,熙熙樓的掌柜王于貴愁眉苦臉地迎上來讥珍,“玉大人,你說我怎么就攤上這事窄瘟≈缘瑁” “怎么了?”我有些...
    開封第一講書人閱讀 152,702評論 0 342
  • 文/不壞的土叔 我叫張陵蹄葱,是天一觀的道長氏义。 經(jīng)常有香客問我,道長图云,這世上最難降的妖魔是什么觅赊? 我笑而不...
    開封第一講書人閱讀 55,259評論 1 279
  • 正文 為了忘掉前任,我火速辦了婚禮琼稻,結(jié)果婚禮上吮螺,老公的妹妹穿的比我還像新娘。我一直安慰自己帕翻,他們只是感情好鸠补,可當我...
    茶點故事閱讀 64,263評論 5 371
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著嘀掸,像睡著了一般紫岩。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發(fā)上睬塌,一...
    開封第一講書人閱讀 49,036評論 1 285
  • 那天泉蝌,我揣著相機與錄音歇万,去河邊找鬼。 笑死勋陪,一個胖子當著我的面吹牛贪磺,可吹牛的內(nèi)容都是我干的。 我是一名探鬼主播诅愚,決...
    沈念sama閱讀 38,349評論 3 400
  • 文/蒼蘭香墨 我猛地睜開眼寒锚,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了违孝?” 一聲冷哼從身側(cè)響起刹前,我...
    開封第一講書人閱讀 36,979評論 0 259
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎雌桑,沒想到半個月后喇喉,有當?shù)厝嗽跇淞掷锇l(fā)現(xiàn)了一具尸體,經(jīng)...
    沈念sama閱讀 43,469評論 1 300
  • 正文 獨居荒郊野嶺守林人離奇死亡校坑,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內(nèi)容為張勛視角 年9月15日...
    茶點故事閱讀 35,938評論 2 323
  • 正文 我和宋清朗相戀三年拣技,在試婚紗的時候發(fā)現(xiàn)自己被綠了。 大學時的朋友給我發(fā)了我未婚夫和他白月光在一起吃飯的照片撒踪。...
    茶點故事閱讀 38,059評論 1 333
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖大渤,靈堂內(nèi)的尸體忽然破棺而出制妄,到底是詐尸還是另有隱情,我是刑警寧澤泵三,帶...
    沈念sama閱讀 33,703評論 4 323
  • 正文 年R本政府宣布耕捞,位于F島的核電站,受9級特大地震影響烫幕,放射性物質(zhì)發(fā)生泄漏俺抽。R本人自食惡果不足惜,卻給世界環(huán)境...
    茶點故事閱讀 39,257評論 3 307
  • 文/蒙蒙 一较曼、第九天 我趴在偏房一處隱蔽的房頂上張望磷斧。 院中可真熱鬧,春花似錦捷犹、人聲如沸弛饭。這莊子的主人今日做“春日...
    開封第一講書人閱讀 30,262評論 0 19
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽侣颂。三九已至,卻和暖如春枪孩,著一層夾襖步出監(jiān)牢的瞬間憔晒,已是汗流浹背藻肄。 一陣腳步聲響...
    開封第一講書人閱讀 31,485評論 1 262
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留拒担,地道東北人嘹屯。 一個月前我還...
    沈念sama閱讀 45,501評論 2 354
  • 正文 我出身青樓,卻偏偏與公主長得像澎蛛,于是被迫代替她去往敵國和親抚垄。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 42,792評論 2 345

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

  • Android 自定義View的各種姿勢1 Activity的顯示之ViewRootImpl詳解 Activity...
    passiontim閱讀 171,509評論 25 707
  • Spring Boot 參考指南 介紹 轉(zhuǎn)載自:https://www.gitbook.com/book/qbgb...
    毛宇鵬閱讀 46,748評論 6 342
  • Spring Cloud為開發(fā)人員提供了快速構建分布式系統(tǒng)中一些常見模式的工具(例如配置管理谋逻,服務發(fā)現(xiàn)呆馁,斷路器,智...
    卡卡羅2017閱讀 134,599評論 18 139
  • 想要做成某件事情的話毁兆,工具是非常重要的浙滤,也就是我們經(jīng)常說的磨刀不誤砍柴工, 工具是非常重要的气堕,就像以前我們?nèi)ヒ粋€地...
    A小蚊子閱讀 133評論 0 1
  • 姓名:張冰 公司:寧波禾隆新材料有限公司 組別:312期努力一組 【日精進打卡第53天】 【知~學習】 《六項精進...
    木頭戲閱讀 140評論 0 0