|
有些同學(xué)向我反映,Java注解老是整不明白,那么筆者就專門寫篇文章來帶同學(xué)們學(xué)習(xí)學(xué)習(xí),順便筆者也復(fù)習(xí)一下。 Java注解詳解Java中的注解可不是注釋,注意區(qū)別。Java注解是跟編譯器直接掛鉤,在JDK1.5之后就出現(xiàn)了注解,那么注解究竟是干嘛的呢?開發(fā)者把它開發(fā)出來是為了干什么的呢? 1.生成文檔。這是最常見的,也是java最早提供的注解。常用的有@see@param@return等,這點都很熟悉,不就是生成自己的API嘛。 2.跟蹤代碼依賴性,實現(xiàn)替代配置文件功能。比較常見的是spring2.5開始的基于注解配置。作用就是減少配置?,F(xiàn)在的框架基本都使用了這種配置來減少配置文件的數(shù)量。 3.在編譯時進(jìn)行格式檢查。如@Override放在方法前,如果你這個方法并不是覆蓋了超類方法,則編譯時就能檢查出。 所以要想成為一名優(yōu)秀的Java開發(fā)程序員,注解的掌握那是必須的。 1.Java中自帶的注解@Override 子類對父類方法的重寫所帶的注解,這個筆者就不多說啦!簡單 @Deprecated 表示已經(jīng)過時,不建議使用,但是依然可以使用 比如你在調(diào)用Thread類的stop方法的時候出現(xiàn)一條橫杠,這就是加了@Deprecated的效果,我截個圖給你看看: 這條杠是編譯器告訴你此方法已經(jīng)過時啦,所以加條杠提示你一下,但是依然可以調(diào)用,并不是不能使用,而是建議不要使用。 @SuppressWarnings 用來抑制編譯時的警告信息,編譯器在你寫代碼的時候,難免會出現(xiàn)很多的警告,有強(qiáng)迫癥的程序猿會感到極其不爽,那么腫么辦呢?@SuppressWarnings注解就可以告訴編譯器,別警告啦,代碼不會有問題的。 比如你想把調(diào)用Thread的stop方法的警告去掉,那么你就可以這么寫: 有的同學(xué)可能不理解@SuppressWarnings(“all”)中的”all”是啥意思?其實很簡單,@SuppressWarnings注解一定要傳遞一個參數(shù)給它,來表示過濾掉哪些類型的警告,筆者添加了”all”表示過濾掉所有類型的警告,很好理解吧!那么還可以傳遞什么參數(shù)來過濾警告呢?看看下面的表格你就會知道啦: 還有一些其它的Java自帶注解,筆者就不一一說明了。 2.自定義注解在學(xué)會自定義注解之前,我們必須先來理解一下Java當(dāng)中用來給自定義注解而注解的元注解,有點繞口哈!沒關(guān)系,其實很簡單,就是說你要自定義一個注解,你必須說明一下這個自定義的注解的使用范圍以及保存注解信息,還有是否包含于Javadoc中,是否允許子類繼承父類中的注解。這4點分別對應(yīng)這4種元注解,看下面的表格你就懂啦: Java4種元注解表格 自定義注解使用關(guān)鍵字@interface,這跟接口有點像,只不過一個”@”符號的差別,還有就是Java注解不支持繼承,示例代碼如下: @Target(value={ElementType.METHOD})//這里表示此注解只能被使用于方法 @Retention(RetentionPolicy.RUNTIME)//通常默認(rèn)使用RUNTIME @Documented @Inherited public@interfaceMyAnnotation{ /*注意在注解當(dāng)中屬性聲明是: *類型+屬性名; *不是聲明一個方法,這一定要區(qū)別開來 */ Stringstr;//注解的屬性聲明,屬性類型為String,名字是'str' } 參考元注解表格,使用”@interface”關(guān)鍵字聲明,注意屬性的聲明末尾是有””的。還有一點就是注解的元素(屬性)只支持: 1.所有的基本類型 2.String 3.Class 4.enum 5.Annotation 6.String,Class,enum,Annotation以及基本類型數(shù)組 其他的類型都會報錯 學(xué)會聲明了,那么如何使用這個注解呢?示例代碼如下: //@MyAnnotation(str='王者榮耀')用在聲明類這里是報錯的,因為筆者的注解@MyAnnotation只能用于方法 publicclassStudent{ publicStringname; publicintage; @MyAnnotation(str='王者榮耀')//用在這里不會報錯 publicvoidplayAndroidGame{ System.out.println(this.name+'玩王者榮耀!'); } } 目前的注解好像用途并沒有完全體現(xiàn)出來,因為你沒有為注解添加注解處理器,沒有添加注解處理器的注解跟注釋沒任何區(qū)別,所以我們必須為注解添加一個注解處理器,才能讓注解的真正用途體現(xiàn)出來,這需要反射的知識,如果你對反射不熟,那么注解處理器怕是有些困難。 3.通過反射創(chuàng)建和使用注解器講解注解器需要一個實例作為參考,我們來設(shè)計這么一個注解器,可以通過注解器來獲取某個類的所有信息。一個類里面會存在屬性,方法,內(nèi)部類,構(gòu)造函數(shù)等,那么我們?nèi)绾瓮ㄟ^注解的方式去獲取到一個類的所有信息呢?首先來設(shè)計我們的注解: 類的注解:元素(屬性)僅包含類名 @Target(value=ElementType.TYPE)//使用范圍類,接口,enum等 //要想通過反射獲取這個注解信息,此注解一定要保留于運行期,所以這里@@Retention必須是RUNTIME的 @Retention(RetentionPolicy.RUNTIME) public@interfaceClassAnnotation{ StringclassName;//類的名字 } 類的屬性的注解:元素(屬性)包含–>屬性名,訪問權(quán)限,屬性類型 @Target(value=ElementType.FIELD)//使用于類的成員屬性 @Retention(RetentionPolicy.RUNTIME) public@interfaceFieldAnnotation{ StringfieldName;//屬性的名字 StringaccessPer;//訪問權(quán)限 StringfieldType;//屬性的類型 } 方法的注解:元素(屬性)包含–>方法名,參數(shù)列表,返回值類型,訪問權(quán)限,方法的功能 @Target(value=ElementType.METHOD)//使用于方法 @Retention(RetentionPolicy.RUNTIME) public@interfaceMethodAnnotation{ StringmethodName;//方法的名字 ClassparameterList;//參數(shù)列表 StringreturnType;//返回值類型 StringaccessPer;//訪問權(quán)限 StringmethodFunction;//方法的功能描述 } 構(gòu)造器的注解:元素(屬性)包含–>構(gòu)造器的名名,參數(shù)列表,返回值類型,訪問權(quán)限 @Target(value=ElementType.CONSTRUCTOR)//使用于構(gòu)造器 @Retention(RetentionPolicy.RUNTIME) public@interfaceConstructorAnnotation{ StringconName;//構(gòu)造器的名字 ClassparameterList;//參數(shù)列表 ClassreturnType;//返回值類型 StringaccessPer;//訪問權(quán)限 } 注解已經(jīng)定義完成,下面一步就是將注解應(yīng)用于一個類當(dāng)中,示例代碼如下: importDate20170810.Annotation.ClassAnnotation; importDate20170810.Annotation.ConstructorAnnotation; importDate20170810.Annotation.FieldAnnotation; importDate20170810.Annotation.MethodAnnotation; @ClassAnnotation(className='Studnet') publicclassStudent{ @FieldAnnotation(fieldName='name',accessPer='private',fieldType='String') privateStringname=''; @FieldAnnotation(fieldName='age',accessPer='private',fieldType='int') privateintage=0; @ConstructorAnnotation(methodName='Studnet',parameterList={String.class,int.class}, returnType=Student.class,accessPer='public') publicStudent(Stringname,intage){ this.age=age; this.name=name; } @MethodAnnotation(methodName='getName',parameterList={},returnType=String.class, accessPer='public',methodFunction='返回當(dāng)前Student實例對象的名字name') publicStringgetName{ returnthis.name; } @MethodAnnotation(methodName='setName',parameterList={String.class},returnType=Void.class, accessPer='public',methodFunction='設(shè)置當(dāng)前Student實例對象的名字name') publicvoidsetName(Stringname){ this.name=name; } @MethodAnnotation(methodName='getAge',parameterList={},returnType=int.class, accessPer='public',methodFunction='返回當(dāng)前Student實例對象的年齡age') publicintgetAge{ returnthis.age; } @MethodAnnotation(methodName='setAge',parameterList={int.class},returnType=Void.class, accessPer='public',methodFunction='設(shè)置當(dāng)前Student實例對象的年齡age') publicvoidsetAge(intage){ this.age=age; } @MethodAnnotation(methodName='playAndroidGame',parameterList={},returnType=Void.class, accessPer='public',methodFunction='王者榮耀有關(guān),就是對小學(xué)生玩王者榮耀太厲害的吐槽!') publicvoidplayAndroidGame{ System.out.println('hello,I'm'+this.name+',今年'+this.age+'歲啦'); if(this.age>12){ System.out.println(this.age+'歲,打王者榮耀還可以不算太坑!'); }else{ System.out.println('由于是小學(xué)生,王者排位就算啦,不如來一盤匹配,'+ '排位萬萬不可!因為啥?怕排位的時候小學(xué)生說我辣雞!'); } } } 下面就是通過反射來獲取Student類的所有信息啦!示例代碼如下: //注解器 publicclassAnnotatorDemo{ //通過反射獲取類的注解信息 publicstaticvoidgetClassAnnotationMessage(Classclass1){ System.out.println('類的注解信息:'); for(java.lang.annotation.Annotationannotation:class1.getDeclaredAnnotations){ System.out.println(annotation); //獲取類注解屬性className的值 if(annotation.annotationType.equals(ClassAnnotation.class)){ StringclassName=((ClassAnnotation)annotation).className; System.out.println('類名:'+className); } } } //通過反射獲取屬性的注解信息 publicstaticvoidgetFieldAnnotationMessage(Classclass1){ System.out.println('屬性注解的信息:'); Fieldfields=class1.getDeclaredFields; for(Fieldfield:fields){ System.out.println; FieldAnnotationfieldAnnotation=field.getDeclaredAnnotation(FieldAnnotation.class); System.out.println(fieldAnnotation); //獲取屬性注解的各種值 StringfieldName=fieldAnnotation.fieldName; System.out.println('屬性名:'+fieldName); StringaccessPer=fieldAnnotation.accessPer; System.out.println('屬性訪問權(quán)限:'+accessPer); ClassfieldType=fieldAnnotation.fieldType; System.out.println('屬性的類型:'+fieldType); } } //獲取構(gòu)造器的注解信息 publicstaticvoidgetConstrutorAnnotationMessage(Classclass1){ System.out.println('構(gòu)造器注解的信息:'); Constructorconstructors=class1.getDeclaredConstructors; for(Constructorconstructor:constructors){ System.out.println; ConstructorAnnotationconstructorAnnotation=constructor.getDeclaredAnnotation(ConstructorAnnotation.class); System.out.println(constructorAnnotation); StringconName=constructorAnnotation.conName; System.out.println('構(gòu)造器的名字:'+conName); System.out.print('構(gòu)造器的參數(shù)列表:'); ClassparameterList=constructorAnnotation.parameterList; for(Classc:parameterList){ System.out.print('['+c.getName+']'); } System.out.println; ClassreturnType=constructorAnnotation.returnType; System.out.println('返回值類型:'+returnType.getName); StringaccessPer=constructorAnnotation.accessPer; System.out.println('訪問權(quán)限:'+accessPer); } } publicstaticvoidgetMethodAnnotationMessage(Classclass1){ System.out.println('方法注解的信息:'); Methodmethods=class1.getDeclaredMethods; for(Methodmethod:methods){ System.out.println; MethodAnnotationmethodAnnotation=method.getDeclaredAnnotation(MethodAnnotation.class); System.out.println(methodAnnotation); StringmethodName=methodAnnotation.methodName; System.out.println('方法的名字:'+methodName); ClassparameterList=methodAnnotation.parameterList; System.out.print('方法參數(shù)參數(shù)列表:'); //判斷參數(shù)列表是否個數(shù)為0 if(parameterList.length==0){ //說明此方法無參 System.out.println('無參'); }else{ //說明此方法有參 for(Classc:parameterList){ System.out.print('['+c.getName+']'); } System.out.println; } ClassreturnType=methodAnnotation.returnType; System.out.println('方法的返回值類型:'+returnType.getName); StringaccessPer=methodAnnotation.accessPer; System.out.println('方法的訪問權(quán)限:'+accessPer); StringmethodFunction=methodAnnotation.methodFunction; System.out.println('方法的功能描述:'+methodFunction); } } publicstaticvoidmain(Stringargs){ Classclass_Student=Student.class; //得到類注解的信息 getClassAnnotationMessage(class_Student); System.out.println('\n'); //得到屬性注解的信息 getFieldAnnotationMessage(class_Student); System.out.println('\n'); //得到構(gòu)造器的注解的信息 getConstrutorAnnotationMessage(class_Student); System.out.println('\n'); //得到方法的注解的信息 getMethodAnnotationMessage(class_Student); } } 運行結(jié)果: 類的注解信息: @Date20170810.Annotation.ClassAnnotation(className=Student) 類名:Student 屬性注解的信息: @Date20170810.Annotation.FieldAnnotation(fieldName=name,accessPer=private,fieldType=classjava.lang.String) 屬性名:name 屬性訪問權(quán)限:private 屬性的類型:classjava.lang.String @Date20170810.Annotation.FieldAnnotation(fieldName=age,accessPer=private,fieldType=int) 屬性名:age 屬性訪問權(quán)限:private 屬性的類型:int 構(gòu)造器注解的信息: @Date20170810.Annotation.ConstructorAnnotation(conName=Studnet,parameterList=[classjava.lang.String,int],returnType=classDate20170810.Student,accessPer=public) 構(gòu)造器的名字:Studnet 構(gòu)造器的參數(shù)列表:[java.lang.String][int] 返回值類型:Date20170810.Student 訪問權(quán)限:public 方法注解的信息: @Date20170810.Annotation.MethodAnnotation(methodName=getName,parameterList=,returnType=classjava.lang.String,accessPer=public,methodFunction=返回當(dāng)前Student實例對象的名字name) 方法的名字:getName 方法參數(shù)參數(shù)列表:無參 方法的返回值類型:java.lang.String 方法的訪問權(quán)限:public 方法的功能描述:返回當(dāng)前Student實例對象的名字name @Date20170810.Annotation.MethodAnnotation(methodName=setName,parameterList=[classjava.lang.String],returnType=classjava.lang.Void,accessPer=public,methodFunction=設(shè)置當(dāng)前Student實例對象的名字name) 方法的名字:setName 方法參數(shù)參數(shù)列表:[java.lang.String] 方法的返回值類型:java.lang.Void 方法的訪問權(quán)限:public 方法的功能描述:設(shè)置當(dāng)前Student實例對象的名字name @Date20170810.Annotation.MethodAnnotation(methodName=setAge,parameterList=[int],returnType=classjava.lang.Void,accessPer=public,methodFunction=設(shè)置當(dāng)前Student實例對象的年齡age) 方法的名字:setAge 方法參數(shù)參數(shù)列表:[int] 方法的返回值類型:java.lang.Void 方法的訪問權(quán)限:public 方法的功能描述:設(shè)置當(dāng)前Student實例對象的年齡age @Date20170810.Annotation.MethodAnnotation(methodName=playAndroidGame,parameterList=,returnType=classjava.lang.Void,accessPer=public,methodFunction=王者榮耀有關(guān),就是對小學(xué)生玩王者榮耀太厲害的吐槽!) 方法的名字:playAndroidGame 方法參數(shù)參數(shù)列表:無參 方法的返回值類型:java.lang.Void 方法的訪問權(quán)限:public 方法的功能描述:王者榮耀有關(guān),就是對小學(xué)生玩王者榮耀太厲害的吐槽! @Date20170810.Annotation.MethodAnnotation(methodName=getAge,parameterList=,returnType=int,accessPer=public,methodFunction=返回當(dāng)前Student實例對象的年齡age) 方法的名字:getAge 方法參數(shù)參數(shù)列表:無參 方法的返回值類型:int 方法的訪問權(quán)限:public 方法的功能描述:返回當(dāng)前Student實例對象的年齡age 一定要自己完成一遍……. 搞明白了這個例子,那么你對注解的掌握就完成了一大半,為什么筆者不寫其他牛的例子,而只寫如何使用注解獲取類的所有信息的例子,因為你只要通過注解獲取到類的所有信息,那么很多框架,包括自己想寫框架,在你一次次寫注解的時候,你就慢慢掌握啦! |
|
|