注解簡介
注解的英文就是 Annotation猜煮,是在JDK 1.5之后引入的一個(gè)特性,與類败许、接口王带、枚舉是在同一個(gè)層次。它可以聲明在包市殷、類愕撰、字段、方法醋寝、局部變量搞挣、方法參數(shù)等的前面,用來對這些元素進(jìn)行說明音羞,注釋柿究。
注解就是給 java 代碼加上一個(gè)標(biāo)識規(guī)則,javac編譯器在編譯時(shí)就會去檢測應(yīng)用了該注解類的類是否符合標(biāo)識規(guī)則黄选,來約束編碼規(guī)范。
元注解
Java目前只內(nèi)置了三種標(biāo)準(zhǔn)注解,以及四種元注解办陷。
1貌夕、@Target
表示支持注解的程序元素的種類,注解該用于什么地方民镜,ElementType
注解修飾的元素類型啡专,使用ElementType
枚舉類來表示:
CONSTRUCTOR:構(gòu)造器的聲明
FIELD:域聲明(包括enum實(shí)例)
LOCAL_VARIABLE:局部變量聲明
METHOD:方法聲明
PACKAGE: 包聲明
PARAMETER:參數(shù)聲明
TYPE:類,接口(包括注解類型)或enum聲明
ANNOTATION_TYPE:注解類型聲明
TYPE_PARAMETER:類型參數(shù)聲明 從jdk1.8開始 制圈、 hide1.8
TYPE_USE:類型的使用 從jdk1.8開始 们童、 hide1.8
2、@Retention
表示保留時(shí)間的長短慧库,需要在什么級別保存該注解信息馋嗜, RetentionPolicy
參數(shù)包括:
SOURCE:注解將被編譯器丟棄。
CLASS:注解在class文件中可用甘磨,但會被VM丟棄济舆。
RUNTIME:VM將在運(yùn)行期也保留注解莺债,因此可通過反射機(jī)制讀取注解的信息。
RetentionPolicy
它是枚舉類椎瘟,分別簡單了解三種類型:
-
RetentionPolicy.SOURCE
當(dāng)注解保留時(shí)期為 SOURCE 時(shí):表示注解信息只會被保留到源碼和編譯期間肺蔚,當(dāng)
javac
編譯器編譯源代碼后會將該注解去除儡羔,但是在編譯期間,注解處理器是是可以處理這些注解的仇冯,在編譯完成之后族操,這些注解信息就沒有了比被。 -
RetentionPolicy.CLASS
當(dāng)注解保留時(shí)期為 CLASS 時(shí):表示注解信息會被保留到編譯時(shí)期,該注解信息會被編譯到
.class
文件中等缀,但不會被虛擬機(jī)加載到內(nèi)存中尺迂,保留到 Javac 將.java
文件編譯成.class
文件冒掌,但是不會隨著 ClassLoader 將該.class
文件加載到內(nèi)存中。 -
RetentionPolicy.RUNTIME
.當(dāng)注解保留時(shí)期為 RUNTIME 時(shí):表示注解信息會被保留到"運(yùn)行時(shí)期"膳音,這是可以通過反射獲取該注解的信息严蓖。
Javac
會將源文件.java
編譯為.class
文件氧急,然后通過 ClassLoader 將.class
文件加載到內(nèi)存中成為字節(jié)碼,這時(shí)就可以通過反射來獲取對應(yīng)的注解信息毒姨。
3钉寝、@Documented
將此注解包含在Javadoc
中。 表示使用該注解的元素應(yīng)被javadoc
或類似工具文檔化俘枫,它應(yīng)用于類型聲明鸠蚪,類型聲明的注解會影響客戶端對注解元素的使用师溅。如果一個(gè)類型聲明添加了Documented注解,那么它的注解會成為被注解元素的公共API的一部分蘸鲸。
4窿锉、@Inherited
允許子類繼承父類中的注解。表示一個(gè)注解類型會被自動繼承妙痹,如果用戶在類聲明的時(shí)候查詢注解類型,同時(shí)類聲明中也沒有這個(gè)類型的注解,那么注解類型會自動查詢該類的父類判沟,這個(gè)過程將會不停地重復(fù),直到該類型的注解被找到為止挪哄,或是到達(dá)類結(jié)構(gòu)的頂層(Object)迹炼。
在開發(fā)中最最常用幾個(gè)注解
-
@Override 約束方法必須從父類中覆寫
復(fù)寫Object 中的equals(Object obj)時(shí)很容將參數(shù)類型定義為當(dāng)前類的類型,如果沒有添加
@Override
的話那系統(tǒng)會認(rèn)為這個(gè)方法并不是繼承至Object的equals方法砂碉,那么使用兩個(gè)對象進(jìn)行比較就會出現(xiàn)問題刻两。 @Deprecated 約束元素已經(jīng)過期,不建議使用滋迈。
@SuppressWarning 壓制警告提示户誓。
通過例子驗(yàn)證如何使用注解
通過編寫代碼,更能了解注解帝美,對注解的概念更能清楚证舟。首先,編寫一個(gè)自定義注解類BindView
:
/**
* @Author lu an
* Create Date is 2019/10/9
* Des 綁定view的注解
*/
//保存的級別到運(yùn)行時(shí)期
@Retention(RetentionPolicy.RUNTIME)
//目標(biāo)->field 字段
@Target(ElementType.FIELD)
public @interface BindView {
int viewId() default 0;//默認(rèn)0
boolean onClick() default false;//default表示默認(rèn)
boolean onLongClick() default false;//default表示默認(rèn)
}
default表示默認(rèn)值 漆枚,也可以不編寫默認(rèn)值的抵知。下面實(shí)現(xiàn)一個(gè)注解工具實(shí)現(xiàn)類:
/**
* @Author lu an
* Create Date is 2019/10/9
* Des 注解工具類
*/
public class InjectUtils {
public static void init(Activity ctx){
//獲取Class對象
Class clazz = ctx.getClass();
//獲取字段變量
Field[]fields = clazz.getDeclaredFields();
for (Field field : fields) {
//判斷是否綁定了BindView
if(field.isAnnotationPresent(BindView.class)){
//獲取到BindView對象
BindView bindView = field.getAnnotation(BindView.class);
//通過getAnnotation方法取出標(biāo)記了注解的字段viewId
int viewId = bindView.viewId();
if(viewId>0){
field.setAccessible(true);
//獲取到view
View childView = ctx.findViewById(viewId);
if (childView != null) {
//綁定的點(diǎn)擊監(jiān)聽事件
if (bindView.onClick() && ctx instanceof View.OnClickListener) {
childView.setOnClickListener((View.OnClickListener) ctx);
}
if (bindView.onLongClick() && ctx instanceof View.OnLongClickListener) {
childView.setOnLongClickListener((View.OnLongClickListener) ctx);
}
}
}
}
}
}
}
通過反射方式,通過getAnnotation
方法取出標(biāo)記了注解的字段viewId立砸,得到了viewId后颗祝,通過上下文findViewById
找到對應(yīng)的View控件,bindView.onClick()
對應(yīng)的@BindView(viewId = R.id.btn_annotation,onClick = true)
中的onClick值螺戳,ctx instanceof View.OnClickListener
則表示Activity是否實(shí)現(xiàn)了點(diǎn)擊接口.
下面就編寫一個(gè)Activity類實(shí)現(xiàn)注解綁定view及其點(diǎn)擊事件:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
//綁定view控件 和 綁定view的點(diǎn)擊事件
@BindView(viewId = R.id.btn_annotation,onClick = true)
Button mBtnAnnotation;
@Override
protected void onCreate(Bundle savedInstanceState) {
super.onCreate(savedInstanceState);
setContentView(R.layout.activity_main);
//注解初始化
InjectUtils.init(this);
}
@Override
public void onClick(View v) {
Toast.makeText(this,"Binding View Success",Toast.LENGTH_SHORT).show();
}
}
@BindView(viewId = R.id.btn_annotation,onClick = true)
表示綁定view控件 和 綁定view的點(diǎn)擊事件倔幼,如果只單單綁定view损同,如@BindView(viewId = R.id.btn_annotation)
即可鸟款。
當(dāng)你點(diǎn)擊Button時(shí)就會彈出Binding View Success。
總結(jié)
- 了解注解的基本概念
- 了解自定義注解與元注解欠雌,注解參數(shù)與默認(rèn)值
- 如何使用注解富俄,通過反射,在運(yùn)行時(shí)動態(tài)獲取注解信息幕袱。當(dāng)然注解的注解不緊緊只有反射,還有APT(編譯時(shí)注解處理器)和插樁(編譯后處理篩選)