企業(yè)網(wǎng)盤怎么下載文件seo是什么服
Java注解以及自定義注解
要深入學(xué)習(xí)注解,我們就必須能定義自己的注解,并使用注解,在定義自己的注解之前,我們就必須要了解Java為
我們提供的元注解和相關(guān)定義注解的語法。
1、注解
1.1 注解的官方定義
注解是一種元數(shù)據(jù)形式。即注解是屬于java的一種數(shù)據(jù)類型,和類、接口、數(shù)組、枚舉類似。
注解用來修飾,類、方法、變量、參數(shù)、包。
注解不會(huì)對(duì)所修飾的代碼產(chǎn)生直接的影響。
1.2 注解的使用范圍
注解有許多用法,其中有:為編譯器提供信息 - 注解能被編譯器檢測到錯(cuò)誤或抑制警告。編譯時(shí)和部署時(shí)的處理 -
軟件工具能處理注解信息從而生成代碼,XML文件等等。運(yùn)行時(shí)的處理 - 有些注解在運(yùn)行時(shí)能被檢測到。
2、元注解
一個(gè)最最基本的注解定義就只包括了兩部分內(nèi)容:1、注解的名字;2、注解包含的類型元素。但是,我們?cè)谑褂?/p>
JDK自帶注解的時(shí)候發(fā)現(xiàn),有些注解只能寫在方法上面(比如@Override);有些卻可以寫在類的上面(比如
@Deprecated)。當(dāng)然除此以外還有很多細(xì)節(jié)性的定義,那么這些定義該如何做呢?接下來就該元注解出場了!
元注解:專門修飾注解的注解。它們都是為了更好的設(shè)計(jì)自定義注解的細(xì)節(jié)而專門設(shè)計(jì)的。Java5.0定義了4個(gè)標(biāo)準(zhǔn)
的meta-annotation類型,它們被用來提供對(duì)其它 annotation類型作說明。
Java5.0 定義的元注解:
1、@Target
2、@Retention
3、@Documented
4、@Inherited
這些類型和它們所支持的類在java.lang.annotation
包中可以找到。下面我們看一下每個(gè)元注解的作用和相應(yīng)
分參數(shù)的使用說明。
2.1 @Target
@Target注解,是專門用來限定某個(gè)自定義注解能夠被應(yīng)用在哪些Java元素上面的。
@Target說明了Annotation所修飾的對(duì)象范圍:Annotation可被用于 packages、types(類、接口、枚舉、
Annotation類型)、類型成員(方法、構(gòu)造方法、成員變量、枚舉值)、方法參數(shù)和本地變量(如循環(huán)變量、
catch參數(shù))。在Annotation類型的聲明中使用了target可更加明晰其修飾的目標(biāo)。
作用:用于描述注解的使用范圍(即被描述的注解可以用在什么地方)
取值(ElementType)有:
1、CONSTRUCTOR
:用于描述構(gòu)造器
2、FIELD
:用于描述域
3、LOCAL_VARIABLE
:用于描述局部變量
4、METHOD
:用于描述方法
5、PACKAGE
:用于描述包
6、PARAMETER
:用于描述參數(shù)
7、TYPE
:用于描述類、接口(包括注解類型) 或enum聲明
它使用一個(gè)枚舉類型定義如下:
public enum ElementType {/** 類,接口(包括注解類型)或枚舉的聲明 */TYPE,/** 屬性的聲明 */FIELD,/** 方法的聲明 */METHOD,/** 方法形式參數(shù)聲明 */PARAMETER,/** 構(gòu)造方法的聲明 */CONSTRUCTOR,/** 局部變量聲明 */LOCAL_VARIABLE,/** 注解類型聲明 */ANNOTATION_TYPE,/** 包的聲明 */PACKAGE,TYPE_PARAMETER,TYPE_USE
}
使用實(shí)例:
package com.test3;import java.lang.annotation.ElementType;
import java.lang.annotation.Target;@Target(ElementType.TYPE)
public @interface Table {/*** 數(shù)據(jù)表名稱注解,默認(rèn)值為類名稱* @return*/public String tableName() default "className";
}
package com.test3;import java.lang.annotation.ElementType;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
public @interface NoDBColumn {
}
package com.test3;import java.lang.annotation.ElementType;
import java.lang.annotation.Target;//@CherryAnnotation被限定只能使用在類、接口或方法上面
@Target(value = {ElementType.TYPE, ElementType.METHOD})
public @interface CherryAnnotation {String name();int age() default 18;int[] array();
}
注解Table
可以用于注解類、接口(包括注解類型) 或enum聲明,而注解NoDBColumn
僅可用于注解類的成員變
量。
2.2 @Retention
@Retention注解,翻譯為持久力、保持力。即用來修飾自定義注解的生命力。
注解的生命周期有三個(gè)階段:1、Java源文件階段;2、編譯到class文件階段;3、運(yùn)行期階段。同樣使用了
RetentionPolicy 枚舉類型定義了三個(gè)階段:
作用:表示需要在什么級(jí)別保存該注釋信息,用于描述注解的生命周期(即被描述的注解在什么范圍內(nèi)有效)
取值(RetentionPoicy)有:
1、SOURCE
:在源文件中有效(即源文件保留)
2、CLASS
:在class文件中有效(即class保留)
3、RUNTIME
:在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留)
Retention meta-annotation類型有唯一的value作為成員,它的取值來自
java.lang.annotation.RetentionPolicy
的枚舉類型值。
public enum RetentionPolicy {// 注解將被編譯器忽略掉SOURCE,// 注解將被編譯器記錄在class文件中,但在運(yùn)行時(shí)不會(huì)被虛擬機(jī)保留,這是一個(gè)默認(rèn)的行為CLASS,// 注解將被編譯器記錄在class文件中,而且在運(yùn)行時(shí)會(huì)被虛擬機(jī)保留,因此它們能通過反射被讀取到RUNTIME
}
我們?cè)僭斀庖幌?#xff1a;
如果一個(gè)注解被定義為RetentionPolicy.SOURCE
,則它將被限定在Java源文件中,那么這個(gè)注解即不會(huì)參與編
譯也不會(huì)在運(yùn)行期起任何作用,這個(gè)注解就和一個(gè)注釋是一樣的效果,只能被閱讀Java文件的人看到;
如果一個(gè)注解被定義為RetentionPolicy.CLASS
,則它將被編譯到Class文件中,那么編譯器可以在編譯時(shí)根據(jù)
注解做一些處理動(dòng)作,但是運(yùn)行時(shí)JVM(Java虛擬機(jī))會(huì)忽略它,我們?cè)谶\(yùn)行期也不能讀取到;
如果一個(gè)注解被定義為RetentionPolicy.RUNTIME
,那么這個(gè)注解可以在運(yùn)行期的加載階段被加載到Class對(duì)象
中。那么在程序運(yùn)行階段,我們可以通過反射得到這個(gè)注解,并通過判斷是否有這個(gè)注解或這個(gè)注解中屬性的值,
從而執(zhí)行不同的程序代碼段。我們實(shí)際開發(fā)中的自定義注解幾乎都是使用的RetentionPolicy.RUNTIME
;在默認(rèn)
的情況下,自定義注解是使用的RetentionPolicy.CLASS
。
具體實(shí)例如下:
package com.test3;import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Column {public String name() default "fieldName";public String setFuncName() default "setField";public String getFuncName() default "getField";public boolean defaultDBValue() default false;
}
Column注解的的RetentionPolicy的屬性值是RUNTIME,這樣注解處理器可以通過反射,獲取到該注解的屬性
值,從而去做一些運(yùn)行時(shí)的邏輯處理。
2.3 @Documented
@Documented注解,是被用來指定自定義注解是否能隨著被定義的java文件生成到JavaDoc文檔當(dāng)中,因此可以
被例如javadoc此類的工具文檔化。
Documented是一個(gè)標(biāo)記注解,沒有成員。
package com.test3;import java.lang.annotation.*;@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Column1 {public String name() default "fieldName";public String setFuncName() default "setField";public String getFuncName() default "getField";public boolean defaultDBValue() default false;
}
2.4 @Inherited
@Inherited注解,是指定某個(gè)自定義注解如果寫在了父類的聲明部分,那么子類的聲明部分也能自動(dòng)擁有該注
解。@Inherited注解只對(duì)那些@Target被定義為ElementType.TYPE
的自定義注解起作用。
@Inherited 元注解是一個(gè)標(biāo)記注解,@Inherited闡述了某個(gè)被標(biāo)注的類型是被繼承的。如果一個(gè)使用了
@Inherited修飾的annotation類型被用于一個(gè)class,則這個(gè)annotation將被用于該class的子類。
注意:@Inherited annotation類型是被標(biāo)注過的class的子類所繼承。類并不從它所實(shí)現(xiàn)的接口繼承annotation,
方法并不從它所重載的方法繼承annotation。
當(dāng)@Inherited annotation類型標(biāo)注的annotation的Retention是RetentionPolicy.RUNTIME,則反射API增強(qiáng)了這
種繼承性。如果我們使用java.lang.reflect去查詢一個(gè)@Inherited annotation類型的annotation時(shí),反射代碼檢查
將展開工作:檢查class和其父類,直到發(fā)現(xiàn)指定的annotation類型被發(fā)現(xiàn),或者到達(dá)類繼承結(jié)構(gòu)的頂層。
實(shí)例代碼:
package com.test3;import java.lang.annotation.Inherited;@Inherited
public @interface Greeting {public enum FontColor {BULE, RED, GREEN};String name();FontColor fontColor() default FontColor.GREEN;
}
注解的繼承依賴如下一個(gè)因素:
1、首先要想Annotation
能被繼承,需要在注解定義的時(shí)候加上@Inherited
,并且如果要被反射應(yīng)用的話,還
需要@Retention(RetentionPolicy.RUNTIME)
標(biāo)識(shí)。
2、JDK文檔中說明的是:只有在類上應(yīng)用Annotation
才能被繼承,而實(shí)際應(yīng)用結(jié)果是:除了類上應(yīng)用的
Annotation
能被繼承外,沒有被重寫的方法的Annotation
也能被繼承。
3、當(dāng)方法被重寫后,Annotation
不會(huì)被繼承。
4、Annotation
的繼承不能應(yīng)用在接口上。
3、自定義注解
使用@interface自定義注解時(shí),自動(dòng)繼承了java.lang.annotation.Annotation接口,由編譯程序自動(dòng)完成其他細(xì)
節(jié)。在定義注解時(shí),不能繼承其他的注解或接口。@interface用來聲明一個(gè)注解,其中的每一個(gè)方法實(shí)際上是聲
明了一個(gè)配置參數(shù)。方法的名稱就是參數(shù)的名稱,返回值類型就是參數(shù)的類型(返回值類型只能是基本類型、
Class、String、enum)。可以通過default來聲明參數(shù)的默認(rèn)值。
3.1 定義注解格式
public @interface 注解名 {定義體}
public @interface CherryAnnotation {
}
根據(jù)我們?cè)谧远x類的經(jīng)驗(yàn),在類的實(shí)現(xiàn)部分無非就是書寫構(gòu)造、屬性或方法。但是,在自定義注解中,其實(shí)現(xiàn)
只能定義一個(gè)東西:注解類型元素(annotation type element)。語法:
public @interface CherryAnnotation {public String name();public int age();public int[] array();
}
public @interface CherryAnnotation {public String name();public int age() default 18;public int[] array();
}
3.2 注解參數(shù)的可支持?jǐn)?shù)據(jù)類型
1、所有基本數(shù)據(jù)類型(int,float,boolean,byte,double,char,long,short
)
2、String
類型
3、Class
類型
4、enum
類型
5、Annotation
類型
6、以上所有類型的數(shù)組
注解里面定義的是:注解類型元素!
3.3 定義注解類型元素時(shí)需要注意如下幾點(diǎn)
1、只能用public或默認(rèn)(default)這兩個(gè)訪問權(quán)修飾,例如String value();
這里把方法設(shè)為default默認(rèn)類型。
2、參數(shù)成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數(shù)據(jù)類型和 String,
Enum,Class,annotations等數(shù)據(jù)類型,以及這一些類型的數(shù)組。
3、如果只有一個(gè)參數(shù)成員,最好把參數(shù)名稱設(shè)為value
,后加小括號(hào)。
4、()
不是定義方法參數(shù)的地方,也不能在括號(hào)中定義任何參數(shù),僅僅只是一個(gè)特殊的語法。
5、default
代表默認(rèn)值,值必須和第2點(diǎn)定義的類型一致。
6、如果沒有默認(rèn)值,代表后續(xù)使用注解時(shí)必須給該類型元素賦值。
可以看出,注解類型元素的語法非常奇怪,即又有屬性的特征(可以賦值),又有方法的特征(打上了一對(duì)括
號(hào))。但是這么設(shè)計(jì)是有道理的,我們?cè)诤竺娴恼鹿?jié)中可以看到:注解在定義好了以后,使用的時(shí)候操作元素類型
像在操作屬性,解析的時(shí)候操作元素類型像在操作方法。
3.4 簡單的自定義注解和使用注解實(shí)例
package com.test;import java.lang.annotation.*;/*** 水果名稱注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {String value() default "";
}
package com.test;import java.lang.annotation.*;/*** 水果顏色注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {/*** 顏色枚舉*/public enum Color {BULE, RED, GREEN};/*** 顏色屬性** @return*/Color fruitColor() default Color.GREEN;}
package com.test;public class Apple {@FruitName("Apple")private String appleName;@FruitColor(fruitColor = FruitColor.Color.RED)private String appleColor;public void setAppleColor(String appleColor) {this.appleColor = appleColor;}public String getAppleColor() {return appleColor;}public void setAppleName(String appleName) {this.appleName = appleName;}public String getAppleName() {return appleName;}
}
3.5 注解元素的默認(rèn)值
注解元素必須有確定的值,要么在定義注解的默認(rèn)值中指定,要么在使用注解時(shí)指定,非基本類型的注解元素的值
不可為null。因此,使用空字符串或0作為默認(rèn)值是一種常用的做法。這個(gè)約束使得處理器很難表現(xiàn)一個(gè)元素的存
在或缺失的狀態(tài),因?yàn)槊總€(gè)注解的聲明中,所有元素都存在,并且都具有相應(yīng)的值,為了繞開這個(gè)約束,我們只能
定義一些特殊的值,例如空字符串或者負(fù)數(shù),一次表示某個(gè)元素不存在,在定義注解時(shí),這已經(jīng)成為一個(gè)習(xí)慣用
法。
package com.test;import java.lang.annotation.*;/*** 水果供應(yīng)者注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {/*** 供應(yīng)商編號(hào)** @return*/public int id() default -1;/*** 供應(yīng)商名稱** @return*/public String name() default "";/*** 供應(yīng)商地址** @return*/public String address() default "";
}
3.6 特殊語法
特殊語法一
如果注解本身沒有注解類型元素,那么在使用注解的時(shí)候可以省略()
,直接寫為:@注解名
,它和標(biāo)準(zhǔn)語法
@注解名()
等效!
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface FirstAnnotation {
}
//等效于 @FirstAnnotation()
@FirstAnnotation
public class JavaBean{
}
特殊語法二
如果注解本身只有一個(gè)注解類型元素,而且命名為value,那么在使用注解的時(shí)候可以直接使用:
@注解名(注解值)
,其等效于:@注解名(value = 注解值)
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface SecondAnnotation {String value();
}
//等效于 @SecondAnnotation(value = "this is second annotation")
@SecondAnnotation("this is annotation")
public class JavaBean{
}
特殊用法三
如果注解中的某個(gè)注解類型元素是一個(gè)數(shù)組類型,在使用時(shí)又出現(xiàn)只需要填入一個(gè)值的情況,那么在使用注解時(shí)可
直接寫為:@注解名(類型名 = 類型值)
,它和標(biāo)準(zhǔn)寫法:@注解名(類型名 = {類型值})
等效!
@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface ThirdAnnotation {String[] name();
}
//等效于 @ThirdAnnotation(name = {"this is third annotation"})
@ ThirdAnnotation(name = "this is third annotation")
public class JavaBean{
}
特殊用法四
如果一個(gè)注解的@Target是定義為Element.PACKAGE,那么這個(gè)注解是配置在package-info.java
中的,而不能
直接在某個(gè)類的package代碼上面配置。
上面三節(jié)定義了注解,并在需要的時(shí)候給相關(guān)類,類屬性加上注解信息,如果沒有響應(yīng)的注解信息處理流程,注解
可以說是沒有實(shí)用價(jià)值。如何讓注解真真的發(fā)揮作用,主要就在于注解處理方法,下一步我們將學(xué)習(xí)注解信息的獲
取和處理!
4、自定義注解的配置使用
基于上一節(jié),已對(duì)注解有了一個(gè)基本的認(rèn)識(shí):注解其實(shí)就是一種標(biāo)記,可以在程序代碼中的關(guān)鍵節(jié)點(diǎn)(類、方法、
變量、參數(shù)、包)上打上這些標(biāo)記,然后程序在編譯時(shí)或運(yùn)行時(shí)可以檢測到這些標(biāo)記從而執(zhí)行一些特殊操作。因此
可以得出自定義注解使用的基本流程:
第一步,定義注解——相當(dāng)于定義標(biāo)記;
第二步,配置注解——把標(biāo)記打在需要用到的程序代碼中;
第三步,解析注解——在編譯期或運(yùn)行時(shí)檢測到標(biāo)記,并進(jìn)行特殊操作。
4.1 在具體的Java類上使用注解
首先,定義一個(gè)注解和一個(gè)供注解修飾的簡單Java類。
package com.test1;import java.lang.annotation.*;@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
@Documented
public @interface CherryAnnotation {String name();// 類型元素int age() default 18;int[] score();
}
package com.test1;public class Student {public void study(int times) {for (int i = 0; i < times; i++) {System.out.println("Good Good Study, Day Day Up!");}}
}
簡單分析下:
CherryAnnotation的@Target定義為ElementType.METHOD,那么它書寫的位置應(yīng)該在方法定義的上方,即:
public void study(int times)之上。由于我們?cè)贑herryAnnotation中定義的有注解類型元素,而且有些元素是沒有
默認(rèn)值的,這要求我們?cè)谑褂玫臅r(shí)候必須在標(biāo)記名后面打上(),并且在()內(nèi)以“元素名=元素值“的形式挨個(gè)填上所有
沒有默認(rèn)值的注解類型元素(有默認(rèn)值的也可以填上重新賦值),中間用“,”號(hào)分割。
所以最終書寫形式如下:
package com.test1;public class Student {@CherryAnnotation(name = "cherry-peng", age = 23, score = {99, 66, 77})public void study(int times) {for (int i = 0; i < times; i++) {System.out.println("Good Good Study, Day Day Up!");}}
}
4.2 自定義注解的運(yùn)行時(shí)解析(反射操作獲取注解)
這一節(jié)是使用注解的核心,讀完此節(jié)即可明白,如何在程序運(yùn)行時(shí)檢測到注解,并進(jìn)行一系列特殊操作!
只有當(dāng)注解的保持力處于運(yùn)行階段,即使用@Retention(RetentionPolicy.RUNTIME)
修飾注解時(shí),才能在JVM
運(yùn)行時(shí),檢測到注解,并進(jìn)行一系列特殊操作。
在運(yùn)行期探究和使用編譯期的內(nèi)容(編譯期配置的注解),要用到Java中的靈魂技術(shù)——反射!
Java SE5擴(kuò)展了反射機(jī)制的API,以幫助程序員快速的構(gòu)造自定義注解處理器。
package com.test1;import java.lang.reflect.Method;/*** @author zhangshixing* @date 2021年11月01日 9:32*/
public class TestAnnotation {public static void main(String[] args){try {//獲取Student的Class對(duì)象Class stuClass = Class.forName("com.test1.Student");//說明一下,這里形參不能寫成Integer.class,應(yīng)寫為int.classMethod stuMethod = stuClass.getMethod("study",int.class);if(stuMethod.isAnnotationPresent(CherryAnnotation.class)){System.out.println("Student類上配置了CherryAnnotation注解!");//獲取該元素上指定類型的注解CherryAnnotation cherryAnnotation = stuMethod.getAnnotation(CherryAnnotation.class);System.out.println("name: " + cherryAnnotation.name() + ", age: " + cherryAnnotation.age()+ ", score: " + cherryAnnotation.score()[0]);}else{System.out.println("Student類上沒有配置CherryAnnotation注解!");}} catch (ClassNotFoundException e) {e.printStackTrace();} catch (NoSuchMethodException e) {e.printStackTrace();}}
}
# 程序輸出
Student類上配置了CherryAnnotation注解!
name: cherry-peng, age: 23, score: 99
4.3 注解處理器類庫(java.lang.reflect.AnnotatedElement)
Java使用Annotation接口來代表程序元素前面的注解,該接口是所有Annotation類型的父接口。除此之外,Java
在java.lang.reflect
包下新增了AnnotatedElement
接口,該接口代表程序中可以接受注解的程序元素,該接
口主要有如下幾個(gè)實(shí)現(xiàn)類:
Class
:類定義
Constructor
:構(gòu)造器定義
Field
:類的成員變量定義
Method
:類的方法定義
Package
:類的包定義
java.lang.reflect
包下主要包含一些實(shí)現(xiàn)反射功能的工具類,實(shí)際上,java.lang.reflect 包所有提供的反射API
擴(kuò)充了讀取運(yùn)行時(shí)Annotation信息的能力。當(dāng)一個(gè)Annotation類型被定義為運(yùn)行時(shí)的Annotation后,該注解才能
是運(yùn)行時(shí)可見,當(dāng)class文件被裝載時(shí)被保存在class文件中的Annotation才會(huì)被虛擬機(jī)讀取。
AnnotatedElement 接口是所有程序元素(Class、Method和Constructor)的父接口,所以程序通過反射獲取了
某個(gè)類的AnnotatedElement對(duì)象之后,程序就可以調(diào)用該對(duì)象的如下四個(gè)個(gè)方法來訪問Annotation信息:
isAnnotationPresent(Class<? extends Annotation> annotationClass)
方法是專門判斷該元素上是否配
置有某個(gè)指定的注解;
getAnnotation(Class<A> annotationClass)
方法是獲取該元素上指定的注解。之后再調(diào)用該注解的注解類型
元素方法就可以獲得配置時(shí)的值數(shù)據(jù);如果該類型注解不存在,則返回null。
反射對(duì)象上還有一個(gè)方法getAnnotations()
,該方法可以獲得該對(duì)象身上配置的所有的注解。它會(huì)返回給我們
一個(gè)注解數(shù)組,需要注意的是該數(shù)組的類型是Annotation類型,這個(gè)Annotation是一個(gè)來自于
java.lang.annotation
包的接口。
Annotation[] getDeclaredAnnotations()
:返回直接存在于此元素上的所有注解。與此接口中的其他方法不
同,該方法將忽略繼承的注解。(如果沒有注解直接存在于此元素上,則返回長度為零的一個(gè)數(shù)組)。該方法的調(diào)
用者可以隨意修改返回的數(shù)組;這不會(huì)對(duì)其它調(diào)用者返回的數(shù)組產(chǎn)生任何影響。
如果我們要獲得的注解是配置在方法上的,那么我們要從Method對(duì)象上獲取;如果是配置在屬性上,就需要從該
屬性對(duì)應(yīng)的Field對(duì)象上去獲取,如果是配置在類型上,需要從Class對(duì)象上去獲取。總之在誰身上,就從誰身上去
獲取!
一個(gè)簡單的注解處理器
/***********注解聲明***************/package com.test2;import java.lang.annotation.*;/*** 水果名稱注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitName {String value() default "";
}
package com.test2;import java.lang.annotation.*;/*** 水果顏色注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitColor {/*** 顏色枚舉** @author peida*/public enum Color {BULE, RED, GREEN};/*** 顏色屬性** @return*/Color fruitColor() default Color.GREEN;}
package com.test2;import java.lang.annotation.*;/*** 水果供應(yīng)者注解*/
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider {/*** 供應(yīng)商編號(hào)** @return*/public int id() default -1;/*** 供應(yīng)商名稱** @return*/public String name() default "";/*** 供應(yīng)商地址** @return*/public String address() default "";
}
/***********注解使用***************/package com.test2;public class Apple {@FruitName("Apple")private String appleName;@FruitColor(fruitColor = FruitColor.Color.RED)private String appleColor;@FruitProvider(id = 1, name = "陜西紅富士集團(tuán)", address = "陜西省西安市延安路89號(hào)紅富士大廈")private String appleProvider;public void setAppleColor(String appleColor) {this.appleColor = appleColor;}public String getAppleColor() {return appleColor;}public void setAppleName(String appleName) {this.appleName = appleName;}public String getAppleName() {return appleName;}public void setAppleProvider(String appleProvider) {this.appleProvider = appleProvider;}public String getAppleProvider() {return appleProvider;}public void displayName() {System.out.println("水果的名字是:蘋果");}
}
/***********注解處理器***************/package com.test2;import java.lang.reflect.Field;public class FruitInfoUtil {public static void getFruitInfo(Class<?> clazz) {String strFruitName = " 水果名稱:";String strFruitColor = " 水果顏色:";String strFruitProvicer = "供應(yīng)商信息:";Field[] fields = clazz.getDeclaredFields();for (Field field : fields) {if (field.isAnnotationPresent(FruitName.class)) {FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class);strFruitName = strFruitName + fruitName.value();System.out.println(strFruitName);} else if (field.isAnnotationPresent(FruitColor.class)) {FruitColor fruitColor = (FruitColor) field.getAnnotation(FruitColor.class);strFruitColor = strFruitColor + fruitColor.fruitColor().toString();System.out.println(strFruitColor);} else if (field.isAnnotationPresent(FruitProvider.class)) {FruitProvider fruitProvider = (FruitProvider) field.getAnnotation(FruitProvider.class);strFruitProvicer = " 供應(yīng)商編號(hào):" + fruitProvider.id() + " 供應(yīng)商名稱:" + fruitProvider.name() + " 供應(yīng)商地址:" + fruitProvider.address();System.out.println(strFruitProvicer);}}}
}
/***********輸出結(jié)果***************/package com.test2;public class FruitRun {/*** @param args*/public static void main(String[] args) {FruitInfoUtil.getFruitInfo(Apple.class);}}
# 程序輸出水果名稱:Apple水果顏色:RED供應(yīng)商編號(hào):1 供應(yīng)商名稱:陜西紅富士集團(tuán) 供應(yīng)商地址:陜西省西安市延安路89號(hào)紅富士大廈