為什么要寫這個祈远,因?yàn)榍岸螘r(shí)間看了一下AOP相關(guān)的一些內(nèi)容膨处,然后也是太久沒寫注解,看得有點(diǎn)那啥不順暢抑党,所以想對注解做個總結(jié)润绎。
一.JAVA自帶的注解
(1)Override 覆蓋
(2)Deprecated 標(biāo)記過期方法
(3)SuppressWarnings 屏蔽警告
二.自定義注解
1.定義
我這里寫個demo自定義一個注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface BindView {
int value() default -1;
}
可以看出注解用@interface來標(biāo)志撬碟。
2.元注解
可以看出在上邊的定義中,上面還有兩個注解莉撇,這些被稱為元注解呢蛤,什么是元注解,簡單來說就是描述注解的注解
還有什么元數(shù)據(jù)的棍郎,元什么什么的其障,這個元其實(shí)不太好解釋,我記得之前看過一個元數(shù)據(jù)的描述涂佃,英文是 data about data励翼,這個元有這個about的那種感覺
元注解有4種
(1)@Retention 用來描述周期,Retention 有“保持時(shí)間”的意思巡李,這個屬性可以選三個值
SOURCE表示只在源碼中有用抚笔,編譯就沒用了。
CLASS表示在編譯中可用侨拦,運(yùn)行就沒用了。
RUNTIME表示運(yùn)行時(shí)可用辐宾。
這三種的區(qū)別解釋起來很麻煩狱从,總之一搬我們都是使用RUNTIME
(2)@Target 用來描述作用域,Target有目標(biāo)的意思叠纹,你這個注解要給哪個目標(biāo)修飾季研,這個屬性可以選以下的值
CONSTRUCTOR用于描述構(gòu)造器
FIELD用于描述域
LOCAL_VARIABLE用于描述局部變量
METHOD用于描述方法
PACKAGE用于描述包
PARAMETER用于描述參數(shù)
這個就是說,你允許把注解寫在什么地方誉察。這個屬性是可以多選的与涡,比如@Target({ElementType.FIELD, ElementType.METHOD})
(3)@Inherited 描述是否可以為繼承,默認(rèn)是false
(4)@Documented 描述是否會保存到 Javadoc 文檔中
一般我們只會用到前面兩個持偏,所以后面兩個我就不解釋了驼卖。
3.注解的值
可以給注解設(shè)置值,比如說我上面的代碼鸿秆,就在注解里寫了個
int value() default -1;
表示在使用注解時(shí)需要傳一個整形的值
@BindView(R.id.tv)
TextView textView;
我這傳了個R.id.tv就是一個整形的值酌畜。只有一個值的時(shí)候,必須以** value()**來命名卿叽,然后調(diào)用時(shí)就直接傳就行桥胞。我還是分情況來說吧恳守。
(1)不需要傳值的情況
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface BindView {
}
調(diào)用
@BindView
TextView textView;
(2)傳一個值的情況
就是我上面寫的代碼
(3)傳多個值的情況
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface BindView {
int age;
String name;
}
調(diào)用
@BindView(age = 18, name = "JackMa")
TextView textView;
最后,這個default 表示設(shè)置默認(rèn)值的意思贩虾。
三.調(diào)用注解
上面我們創(chuàng)建出了注解并定義好催烘,然后我們需要調(diào)用這個注解,那怎么調(diào)用呢缎罢,一般我們調(diào)用一個類或接口都是new 出來伊群,但是這東西怎么看都覺得new不出來吧,所以我們需要用反射來獲取到注解的對象屁使,然后進(jìn)行調(diào)用
我不想去講反射的內(nèi)容在岂,不然就沒完了。就說個思路蛮寂,需要用到哪個方法可以去查api蔽午。
注解在Java中就是Annotation懂吧,所以在反射中和Annotation相關(guān)的方法都是和注解相關(guān)的方法酬蹋。
比如說獲取注解及老,我就可以調(diào)用.getAnnotation(BindView.class)
再比如說我判斷注解存在不,可以調(diào)用isAnnotationPresent()
總之你只要記住注解是Annotation范抓,之后你不管是在反射中還是在哪里找和注解相關(guān)的方法骄恶,都先往Annotation這個名詞相關(guān)的地方找準(zhǔn)沒錯。
如果你不懂反射這里說再多也沒有匕垫。
四.案例
其實(shí)說了這么多僧鲁,到底哪里需要使用到注解呢,如果不使用到象泵,講它有啥用寞秃,我個人是目前接觸到AOP涉及注解比較頻繁,其它時(shí)候偶惠,比如說ButterKnife春寿,Dagger,Retrofit等等這些主流的框架都會用到注解忽孽,包括java后臺绑改,我接觸過spring會涉及到IOC啊AOP啊這些思想用java來實(shí)現(xiàn)也是用到注解比較多,所以可以來寫個小demo試試兄一。
不如就仿照ButterKnife吧厘线,我之前沒看過ButterKnife的源碼啊,我就按照我學(xué)會的注解的知識和ButterKnife的調(diào)用方法來仿寫個ButterKnife
1.首先定義注解
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.FIELD})
public @interface BindView {
int value() default -1;
}
定義注解瘾腰,要求傳個資源進(jìn)來皆的,默認(rèn)是-1
2.按照ButterKnife的調(diào)用的樣子來寫調(diào)用的地方
public class MainActivity extends AppCompatActivity {
@BindView(R.id.tv)
TextView textView;
@BindView(R.id.btn)
Button btn;
String yyy = "aasdasdas";
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
ButterKnife.bind(this);
textView.setText("wwwwwwwwwwwwww");
btn.setText("btn");
}
}
發(fā)現(xiàn)ButterKnife調(diào)用的地方使用這 ButterKnife.bind(this); 那我就推測findViewById就在這個ButterKnife類的bind方法中進(jìn)行。
3.定義ButterKnife
public class ButterKnife {
public static void bind(Activity activity){
Class<?> cls = activity.getClass();
Field[] fields = cls.getDeclaredFields();
for (Field field : fields) {
BindView bindView = field.getAnnotation(BindView.class);
if (bindView != null) {
int ids = bindView.value();
try {
field.set(activity, activity.findViewById(ids));
} catch (IllegalAccessException e) {
e.printStackTrace();
}
}
}
}
}
我這里就用了反射來操作蹋盆,調(diào)用bind方法后费薄,先用cls.getDeclaredFields();獲取所有的全局變量硝全,然后再對每個變量用field.getAnnotation(BindView.class);來獲取這個變量上面的注解,如果存在的話 int ids = bindView.value(); 來獲取我們傳入的資源楞抡,最后調(diào)用findViewById
field.set(activity, activity.findViewById(ids));
很簡單吧伟众,三個類這樣就能實(shí)現(xiàn)了ButterKnife的效果
注意判空一定要寫,即使你全部的變量都用了注解召廷,但是如果你DeBug看看凳厢,你會發(fā)現(xiàn),變量中不僅僅只有你定義的竞慢,還存在其他的先紫。
其實(shí)上面都是瞎寫的,ButterKnife的原理根本不是這樣筹煮,雖然我沒看過源碼遮精,但我聽別人說過ButterKnife的實(shí)現(xiàn)并不是這樣的,我這的demo只是仿照了這個功能败潦,具體ButterKnife的原理以后如果有時(shí)間我會單獨(dú)寫本冲。
通過上面的講解就能簡單的實(shí)現(xiàn)注解,我也順便復(fù)習(xí)加總結(jié)了一遍劫扒。