Java5開始,Java開始對中繼資料的支援,也就是annotation(註解/標籤)
中繼資料:metadata:描述資料的資料:
所有的Annotation都是java.lang.annotation.Annotation介面的子介面,所以Annotation是一種特殊的介面(枚舉也是特殊的類)
枚舉:所有的枚舉類型都是java.lang.Enum類的子類。--->枚舉是一種特殊的類。
註解:所有的註解都是java.lang.annotation.Annotation介面的子介面,註解是一種特殊的介面。
使用註解:
注意:註解本身不具有任何功能,得提供第三方的程式來賦予它功能。
使用註解有三方程式參與:
1、首先必須存在一個註解類;
2、其次必須存在被貼的程式元素;
3、必須有第三方的程式來賦予註解特殊的功能(反射操作)。
在Java中,內建有5個註解:(Java5出現3個,Java7出現1個,Java8出現1個):
@Override 限定子類是否覆寫父類方法
@Deprecated 標記已淘汰,過時的方法/類不推薦使用
@SuppressWarings 抑制編譯器發出的警告,僅僅是抑制警告,問題依然存在
@SuppressWarings(value="all")
@safeVarargs 抑制堆汙染警告(Java7開始出現的)
@FunctionalInterface Java8出現,表示函數式介面,只允許該介面中只有一個抽象方法。如果一個介面中就只有一個抽象方法,也可以不使用註解。可以運用函數式編程(lambda文法)。
Java5才開始出現註解,才開始有@Deprecated註解,但是java.util.Date類中在JDK1.1的時候很多方法就過時了:
在Java5之前標記某一個方法過時,使用文檔注釋。
/** * Created by Layne_Yao on 2017-8-5 上午9:51:42. * CSDN:http://blog.csdn.net/Jsagacity */public class AnnotationDemo {//從Java5開始@Deprecatedpublic void annotation1() {}//在Java5之前/** * @deprecated */public void annotation2() {}public static void main(String[] args) {}}
註解:用來貼在類,方法,構造器,欄位,參數等之上,用於給被貼的程式元素賦予一定的功能。
元註解:在註解定義的時候,必須使用元註解來標註,元註解的註解。
@Retention:決定了註解可以保持在哪一個時期,一共三個時期,都封裝在RetentionPolicy枚舉類中:
SOURCE:該註解在編譯時間期就會丟棄,不會存在於位元組碼檔案中,只能存在於源檔案中;
CLASS:該註解可以存在源檔案和位元組碼檔案中,但是一旦載入進JVM,就丟失;
RUNTIME:該註解可以存在源檔案,位元組碼,JVM中。
自訂的註解類,都是要RUNTIME,因為我們需要在運行時期通過反射賦予註解特殊功能。
@Target:決定了註解可以貼在哪些成員元素之上。可以貼的成員元素都很多,都封裝在ElementType枚舉類中。
ElementType.ANNOTATION_TYPE 只能修飾注釋型別宣告
ElementType.CONSTRUCTOR 只能修飾構造方法聲明
ElementType.FIELD 只能修飾欄位聲明(包括枚舉常量)
ElementType.LOCAL_VARIABLE 只能修飾局部變數聲明
ElementType.METHOD 只能修飾方法聲明
ElementType.PACKAGE 只能修飾包聲明
ElementType.PARAMETER 只能修飾參數聲明
ElementType.TYPE 只能修飾類、介面(包括注釋類型)或枚舉聲明
@Documentd:使用@Documentd標註的標籤會儲存字API文檔中。
@Inherited:@Inherited標註的標籤可以被子類所繼承。
在Class,Method,Field,Constructor中有擷取/判斷註解存在的方法
常用的API:
Annotation getAnnotation(Class annotationClass):判斷當前類、方法、欄位上是否擁有指定的註解,若有,則返回當前對象,若沒有返回null;
Annotation[] getAnnotations():返回此元素上存在的所有注釋。
boolean isAnnotationPresent(Class annotationClass):如果指定類型的注釋存在於此元素上,則返回 true,否則返回 false。
註解類:
//定義註解@Target(ElementType.TYPE)//只能修飾類、介面(包括注釋類型)或枚舉聲明 @Retention(RetentionPolicy.RUNTIME)//該註解可以存在源檔案,位元組碼,JVM中。public @interface INFO {//註解是特殊的介面,介面中有抽象方法,在註解八抽象方法稱為屬性String username();int age() default 20;//default是設定預設值String[] hobby();Gender sex() default Gender.NONE;}
Gender需要設定成public:
/** * Created by Layne_Yao on 2017-8-5 上午11:11:03. * CSDN:http://blog.csdn.net/Jsagacity */public enum Gender{BOY,GIRL,NONE;}
賦予特殊功能得類:
/** * Created by Layne_Yao on 2017-8-5 上午9:51:42. * CSDN:http://blog.csdn.net/Jsagacity */// 被貼程式元素@INFO(username = "Layne", age = 18, sex = Gender.BOY, hobby = { "Java","Android", "C++" })class User {@Deprecatedpublic void doWork() {}}// 賦予註解特殊功能得public class AnnotationDemo1 {public static void main(String[] args) throws Exception {// 擷取Person類上的VIP註解中的資訊Class cls = User.class;// 擷取Person類上所有的註解Annotation[] as = cls.getAnnotations();// 判斷Person類上是否有VIP註解boolean isPresent = cls.isAnnotationPresent(INFO.class);if (isPresent) {// 取出Person類上的註解Annotation a = cls.getAnnotation(INFO.class);// 擷取VIP註解中的屬性值(調用VIP的抽象方法)INFO vip = (INFO) a;System.out.println(vip.username());System.out.println(vip.age());System.out.println(vip.sex());}// 需求:擷取doWork方法上的Deprecated註解// 1:擷取doWork方法所在類的位元組碼檔案Class doWorkCls = User.class;// 2:擷取doWork方法的Method對象Method m = doWorkCls.getMethod("doWork");System.out.println(m);// 3:擷取當前方法上的註解Deprecated depre = m.getAnnotation(Deprecated.class);System.out.println(depre);}}
運行結果:
上面程式並沒有賦予註解功能。
接下來建立一個Android項目,布局檔案裡面添加兩個控制項:
<RelativeLayout xmlns:android="http://schemas.android.com/apk/res/android" xmlns:tools="http://schemas.android.com/tools" android:layout_width="match_parent" android:layout_height="match_parent" tools:context="com.example.annomationdemo.MainActivity" > <TextView android:id="@+id/tv_show" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_alignParentTop="true" android:layout_centerHorizontal="true" android:layout_marginTop="180dp" android:text="@string/hello_world" /> <Button android:id="@+id/bt_show" android:layout_width="wrap_content" android:layout_height="wrap_content" android:layout_centerHorizontal="true" android:layout_centerVertical="true" android:text="Button" /></RelativeLayout>
建立一個註解類:
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 getViewTo { int value() default -1;}
MainActivity.java中:
public class MainActivity extends ActionBarActivity {@getViewTo(R.id.tv_show)private TextView tv_show;@getViewTo(R.id.bt_show)private Button bt_show; @Override protected void onCreate(Bundle savedInstanceState) { super.onCreate(savedInstanceState); setContentView(R.layout.activity_main); //通過註解產生View getAllAnnomationView(); bt_show.setOnClickListener(new OnClickListener() {@Overridepublic void onClick(View v) {tv_show.setText("註解擷取成功");}}); } /** * 解析註解,擷取控制項 */private void getAllAnnomationView() {//擷取成員變數Field[] fields = this.getClass().getDeclaredFields();for (Field field : fields) {try {//判斷註解是否為空白if(field.getAnnotations()!=null){//確定註解類型if(field.isAnnotationPresent(getViewTo.class)){//允許修改反射屬性field.setAccessible(true);getViewTo getViewTo = field.getAnnotation(getViewTo.class);//通過findViewById將註解的id,找到View並注入成員變數中field.set(this, findViewById(getViewTo.value()));}}} catch (IllegalAccessException e) {e.printStackTrace();} catch (IllegalArgumentException e) {e.printStackTrace();}}}}
這裡就不示範運行結果了,大家運行過後可能有點感覺像ButterKnife,不過ButterKnife比這個強大多了。