Java的注解

注解可以為Java代碼中添加信息,然后在某個時刻去運用它。Java內置了三種注解,分別為:

@Override,(表示當前方法覆蓋超類的方法)

@Deprecated,(如果使用了含有此注解的元素,編譯器將會警告)

@SuppressWarnings.(關閉編譯器的警告信息)

一,定義注解

Java提供了四種注解來負責新注解的創建,分別是

@Tartget:

表示該注解用在什么地方,參數包括:

CONSTRUCTOR:構造器的聲明

FIELD:域聲明

LOCAL_VARIABLE:局部變量聲明

METHOD:方法聲明

PACKIAGE:包聲明

TYPE:類,接口或enum聲明

@Retention:

表示在哪個級別保存注解信息,參數包括:

SOURCE::注解會被編譯器丟棄

CLASS:注解在class文件中可以用

RUNTIME:運行期保留注解,可以通過反射機制讀取注解的信息

@Documented?

將此注解包含在Javadoc中

@Inherited

允許子類繼承父類的注解

例子:要定義在方法上一個運行時注解

@Tartget(ElementType.METHOD)

@Retention(RetentionPolicy.RUNTIME)

public @interface Test{

}


使用時如下:

class H{

@Test

void someMethod(){

}

}

在運行時,可以通過反射獲取@Test的信息

二,注解處理

標記在代碼的注解可以在運行時通過反射獲取其信息

for(mothod m : H.getDeclaredMethods()){

Test test=m.getAnnotation(Test.class)

if(test != null){

//找到注解信息,進行處理

? ? }

}

三,注解在Android中的應用

在Android開發中,經常會根據控件id獲取控件實例,例如獲取一個按鈕實例,并設置點擊事件

Button btn=(Button)findviewbyid(R.id.xxxx);

btn.setOnClickListener(xxx);

大部分情況下,編寫一個Activity頁面時,都會設置大量的按鈕,那么都要寫大量同樣樣式的代碼,為什么不交給程序去完成這種繁復的勞動呢?

我們可以省掉寫這些代碼的時間,可以利用注解來解決。

首先,定義注解,按鈕有兩個基本作用,一是獲取實例便于稍后做其它操作,二是設置點擊事件,由此可以這樣定義:

@Target(ElementType.FIELD)

@Retention(RetentionPolicy.RUNTIME)

public @interface ButtonHandle {

public ?int ?id();

public ?boolean ?click() ?default ? false;

}

@Target標識該注解用于變量上,@Retention說明該注解用于運行時,注解名稱為ButtonHandle,有兩個屬性,int類型屬性id對于布局中的R.id.xxx

boolean類型屬性click標識是否設置點擊事件。使用如下:

@ButtonHandle(id = R.id.xxx, click =true)

private? Button ?btn;

這個注解的作用是把id為R.id.xxx的控件實例賦值給btn,并設置btn的點擊事件。

下面來實現這個注解的功能,需要寫一個注解處理器,先寫關鍵代碼:

public ?static ?void ? ButtonHandle(Object activity, View sourceView) {

//?通過反射獲取到全部屬性

Field[] fields = activity.getClass().getDeclaredFields();

if(fields?!=null&&?fields.length?>0)?{

for(Field?field?:?fields)?{

// 返回ButtonHandle類型的注解內容

BindView bindView = field.getAnnotation(ButtonHandle.class);

if(bindView?!=null)?{

//獲取標記在注解上的id

intviewId?=?bindView.id();

//是否設置點擊事件

boolean ?clickLis?=?bindView.click();

try{

field.setAccessible(true);

if(clickLis)?{

//注解幫我們完成的事,設置點擊事件

sourceView.findViewById(viewId).setOnClickListener(

(OnClickListener) activity);

}

//注解幫我們完成的事,賦值

field.set(activity, sourceView.findViewById(viewId));

}catch(Exception e) {

e.printStackTrace();

}

}

}

}

}

上面的代碼完成獲取實例并給按鈕設置點擊事件, activity表示當前activity, sourceView表示activity的根view,即DecorView,在onCreate()里

調用以上方法即可完成注解的處理,給Btton設置點擊事件。

四,編譯時注解

運行時注解的處理用到了反射,假如在意反射損耗的性能,可以考慮使用編譯時注解,可以利用編譯時動態生成想要源代碼,實現相關功能。

在Android studio 中新建一個java Library的Module,在里面實現一個注解處理器,該處理器繼承自AbstractProcessor,重寫getSupportedAnnotationTypes()和process()方法:

public classMyProcessorextendsAbstractProcessor {

privateFilerfiler;

@Override

public synchronized voidinit(ProcessingEnvironment processingEnv) {

super.init(processingEnv);

// Filer

filer= processingEnv.getFiler();

}

@Override

public booleanprocess(Set annotations,RoundEnvironment roundEnv) {

for(TypeElement element : annotations) {

if(element.getQualifiedName().toString().equals(MyAnnotation.class.getCanonicalName())) {

MethodSpec main = MethodSpec.methodBuilder("main")

//? ? ? ? ? ? ? ? ? ? ? ? .addModifiers(Modifier.PUBLIC, Modifier.STATIC)

.returns(void.class)

.addParameter(String[].class,"args")

.addStatement("$T.out.println($S)",System.class,"Hello, JavaPoet!")

.build();

TypeSpec helloWorld = TypeSpec.classBuilder("HelloWorld")

//? ? ? ? ? ? ? ? ? ? ? ? .addModifiers(Modifier.PUBLIC, Modifier.FINAL)

.addMethod(main)

.build();

JavaFile javaFile = JavaFile.builder("com.example.helloworld",helloWorld)

.build();

try{

javaFile.writeTo(newFile(filer);

}catch(IOException e) {

e.printStackTrace();

}

}

}

return true;

}

@Override

publicSetgetSupportedAnnotationTypes() {

Set annotataions =newLinkedHashSet();

annotataions.add(MyAnnotation.class.getCanonicalName());

returnannotataions;

}

@Override

publicSourceVersiongetSupportedSourceVersion() {

returnSourceVersion.latestSupported();

}


新建一個注解的module,定義注解:

@Retention(RetentionPolicy.CLASS)

@Target(ElementType.TYPE)

public@interfaceMyAnnotation{

Stringvalue();

}

寫完后好需要配置,在main文件夾下創建一個resources.META-INF.services文件夾,創建文件

javax.annotation.processing.Processor,文件內容是Process類的包名+類名。


然后在要使用注解的module依賴包含注解處理器的module和包含注解定義的module,并使用:


然后Build該Module。完成后,打開build文件夾,生成的代碼在該文件夾下,可以直接利用其功能。


最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。
  • 序言:七十年代末,一起剝皮案震驚了整個濱河市,隨后出現的幾起案子,更是在濱河造成了極大的恐慌,老刑警劉巖,帶你破解...
    沈念sama閱讀 228,983評論 6 537
  • 序言:濱河連續發生了三起死亡事件,死亡現場離奇詭異,居然都是意外死亡,警方通過查閱死者的電腦和手機,發現死者居然都...
    沈念sama閱讀 98,772評論 3 422
  • 文/潘曉璐 我一進店門,熙熙樓的掌柜王于貴愁眉苦臉地迎上來,“玉大人,你說我怎么就攤上這事。” “怎么了?”我有些...
    開封第一講書人閱讀 176,947評論 0 381
  • 文/不壞的土叔 我叫張陵,是天一觀的道長。 經常有香客問我,道長,這世上最難降的妖魔是什么? 我笑而不...
    開封第一講書人閱讀 63,201評論 1 315
  • 正文 為了忘掉前任,我火速辦了婚禮,結果婚禮上,老公的妹妹穿的比我還像新娘。我一直安慰自己,他們只是感情好,可當我...
    茶點故事閱讀 71,960評論 6 410
  • 文/花漫 我一把揭開白布。 她就那樣靜靜地躺著,像睡著了一般。 火紅的嫁衣襯著肌膚如雪。 梳的紋絲不亂的頭發上,一...
    開封第一講書人閱讀 55,350評論 1 324
  • 那天,我揣著相機與錄音,去河邊找鬼。 笑死,一個胖子當著我的面吹牛,可吹牛的內容都是我干的。 我是一名探鬼主播,決...
    沈念sama閱讀 43,406評論 3 444
  • 文/蒼蘭香墨 我猛地睜開眼,長吁一口氣:“原來是場噩夢啊……” “哼!你這毒婦竟也來了?” 一聲冷哼從身側響起,我...
    開封第一講書人閱讀 42,549評論 0 289
  • 序言:老撾萬榮一對情侶失蹤,失蹤者是張志新(化名)和其女友劉穎,沒想到半個月后,有當地人在樹林里發現了一具尸體,經...
    沈念sama閱讀 49,104評論 1 335
  • 正文 獨居荒郊野嶺守林人離奇死亡,尸身上長有42處帶血的膿包…… 初始之章·張勛 以下內容為張勛視角 年9月15日...
    茶點故事閱讀 40,914評論 3 356
  • 正文 我和宋清朗相戀三年,在試婚紗的時候發現自己被綠了。 大學時的朋友給我發了我未婚夫和他白月光在一起吃飯的照片。...
    茶點故事閱讀 43,089評論 1 371
  • 序言:一個原本活蹦亂跳的男人離奇死亡,死狀恐怖,靈堂內的尸體忽然破棺而出,到底是詐尸還是另有隱情,我是刑警寧澤,帶...
    沈念sama閱讀 38,647評論 5 362
  • 正文 年R本政府宣布,位于F島的核電站,受9級特大地震影響,放射性物質發生泄漏。R本人自食惡果不足惜,卻給世界環境...
    茶點故事閱讀 44,340評論 3 347
  • 文/蒙蒙 一、第九天 我趴在偏房一處隱蔽的房頂上張望。 院中可真熱鬧,春花似錦、人聲如沸。這莊子的主人今日做“春日...
    開封第一講書人閱讀 34,753評論 0 28
  • 文/蒼蘭香墨 我抬頭看了看天上的太陽。三九已至,卻和暖如春,著一層夾襖步出監牢的瞬間,已是汗流浹背。 一陣腳步聲響...
    開封第一講書人閱讀 36,007評論 1 289
  • 我被黑心中介騙來泰國打工, 沒想到剛下飛機就差點兒被人妖公主榨干…… 1. 我叫王不留,地道東北人。 一個月前我還...
    沈念sama閱讀 51,834評論 3 395
  • 正文 我出身青樓,卻偏偏與公主長得像,于是被迫代替她去往敵國和親。 傳聞我的和親對象是個殘疾皇子,可洞房花燭夜當晚...
    茶點故事閱讀 48,106評論 2 375

推薦閱讀更多精彩內容