注解簡介
注解的英文就是 Annotation,是在JDK 1.5之后引入的一個特性,與類、接口、枚舉是在同一個層次。它可以聲明在包、類、字段、方法、局部變量、方法參數(shù)等的前面,用來對這些元素進行說明,注釋。
注解就是給 java 代碼加上一個標識規(guī)則,javac編譯器在編譯時就會去檢測應(yīng)用了該注解類的類是否符合標識規(guī)則,來約束編碼規(guī)范。
元注解
Java目前只內(nèi)置了三種標準注解,以及四種元注解。
1、@Target
表示支持注解的程序元素的種類,注解該用于什么地方,ElementType 注解修飾的元素類型,使用ElementType枚舉類來表示:
CONSTRUCTOR:構(gòu)造器的聲明
FIELD:域聲明(包括enum實例)
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
表示保留時間的長短,需要在什么級別保存該注解信息, RetentionPolicy參數(shù)包括:
SOURCE:注解將被編譯器丟棄。
CLASS:注解在class文件中可用,但會被VM丟棄。
RUNTIME:VM將在運行期也保留注解,因此可通過反射機制讀取注解的信息。
RetentionPolicy 它是枚舉類,分別簡單了解三種類型:
-
RetentionPolicy.SOURCE
當(dāng)注解保留時期為 SOURCE 時:表示注解信息只會被保留到源碼和編譯期間,當(dāng)
javac編譯器編譯源代碼后會將該注解去除,但是在編譯期間,注解處理器是是可以處理這些注解的,在編譯完成之后,這些注解信息就沒有了。 -
RetentionPolicy.CLASS
當(dāng)注解保留時期為 CLASS 時:表示注解信息會被保留到編譯時期,該注解信息會被編譯到
.class文件中,但不會被虛擬機加載到內(nèi)存中,保留到 Javac 將.java文件編譯成.class文件,但是不會隨著 ClassLoader 將該.class文件加載到內(nèi)存中。 -
RetentionPolicy.RUNTIME
.當(dāng)注解保留時期為 RUNTIME 時:表示注解信息會被保留到"運行時期",這是可以通過反射獲取該注解的信息。
Javac會將源文件.java編譯為.class文件,然后通過 ClassLoader 將.class文件加載到內(nèi)存中成為字節(jié)碼,這時就可以通過反射來獲取對應(yīng)的注解信息。
3、@Documented
將此注解包含在Javadoc中。 表示使用該注解的元素應(yīng)被javadoc或類似工具文檔化,它應(yīng)用于類型聲明,類型聲明的注解會影響客戶端對注解元素的使用。如果一個類型聲明添加了Documented注解,那么它的注解會成為被注解元素的公共API的一部分。
4、@Inherited
允許子類繼承父類中的注解。表示一個注解類型會被自動繼承,如果用戶在類聲明的時候查詢注解類型,同時類聲明中也沒有這個類型的注解,那么注解類型會自動查詢該類的父類,這個過程將會不停地重復(fù),直到該類型的注解被找到為止,或是到達類結(jié)構(gòu)的頂層(Object)。
在開發(fā)中最最常用幾個注解
-
@Override 約束方法必須從父類中覆寫
復(fù)寫Object 中的equals(Object obj)時很容將參數(shù)類型定義為當(dāng)前類的類型,如果沒有添加
@Override的話那系統(tǒng)會認為這個方法并不是繼承至Object的equals方法,那么使用兩個對象進行比較就會出現(xiàn)問題。 @Deprecated 約束元素已經(jīng)過期,不建議使用。
@SuppressWarning 壓制警告提示。
通過例子驗證如何使用注解
通過編寫代碼,更能了解注解,對注解的概念更能清楚。首先,編寫一個自定義注解類BindView :
/**
* @Author lu an
* Create Date is 2019/10/9
* Des 綁定view的注解
*/
//保存的級別到運行時期
@Retention(RetentionPolicy.RUNTIME)
//目標->field 字段
@Target(ElementType.FIELD)
public @interface BindView {
int viewId() default 0;//默認0
boolean onClick() default false;//default表示默認
boolean onLongClick() default false;//default表示默認
}
default表示默認值 ,也可以不編寫默認值的。下面實現(xiàn)一個注解工具實現(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方法取出標記了注解的字段viewId
int viewId = bindView.viewId();
if(viewId>0){
field.setAccessible(true);
//獲取到view
View childView = ctx.findViewById(viewId);
if (childView != null) {
//綁定的點擊監(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方法取出標記了注解的字段viewId,得到了viewId后,通過上下文findViewById找到對應(yīng)的View控件,bindView.onClick() 對應(yīng)的@BindView(viewId = R.id.btn_annotation,onClick = true)中的onClick值,ctx instanceof View.OnClickListener則表示Activity是否實現(xiàn)了點擊接口.
下面就編寫一個Activity類實現(xiàn)注解綁定view及其點擊事件:
public class MainActivity extends AppCompatActivity implements View.OnClickListener{
//綁定view控件 和 綁定view的點擊事件
@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的點擊事件,如果只單單綁定view,如@BindView(viewId = R.id.btn_annotation)即可。
當(dāng)你點擊Button時就會彈出Binding View Success。
總結(jié)
- 了解注解的基本概念
- 了解自定義注解與元注解,注解參數(shù)與默認值
- 如何使用注解,通過反射,在運行時動態(tài)獲取注解信息。當(dāng)然注解的注解不緊緊只有反射,還有APT(編譯時注解處理器)和插樁(編譯后處理篩選)