閱讀102 返回首頁    go 阿裏雲 go 技術社區[雲棲]


注解詳細

一、什麼是注解?

        注解(annotation-也稱元數據)為我們在代碼中添加信息提供了一種形式化的方法,使我們可以在稍後某個時刻非常方便地使用這些數據。----------------Thinking in Java書中的第20章

        簡單地說,注解相當於一種標記,加了注解就等於打上了某種標記,如果你加了標記,那javac(java編譯器)或開發工具或其他的程序就可以用反射來了解你的類及類中的各個元素上有沒有標記,有什麼標記,就去幹與標記相關的事。標記可以加在包、類、字段、方法、方法中的參數和局部變量上,可以簡單理解為標記可以加在類中所有元素的身上。

二、注解的優點

       1.它們可以提供用來完整地描述程序所需的信息,而這些信息是無法用Java來表達的,因此注解使得我們能夠以將由編譯器來測試和驗證的格式,存儲有關程序的額外信息。

       2.注解是在實際的源代碼級別保存所有的信息,而不是某種注釋性的文字,這使得代碼更整潔,且便於維護。

       3.減少配置文件的數量。

三、注解的作用

      1.生成文檔。這是最常見的,也是java最早提供的注解。常用的有@see,@param,@return等

      2.跟蹤代碼依賴性,實現替代配置文件功能。比較常見的是spring 2.5開始的基於注解配置。作用就是減少配置。現在的框架基本都使用了這種配置來減少配置文件的數量。

      3.在編譯時進行格式檢查。如@Override放在方法前,如果你這個方法並不是覆蓋了父類(也叫超類)的方法,則編譯時就能檢查出來。

四、使用注解的情況

       1.假如我在寫程序時,曾經寫了一個方法public static void sayHello(){System.out.println("hi,傳智播客");},隨著時間的流逝,我要升級程序了,但是發現這個sayHello()方法不怎麼好,我不想用了,那怎麼辦?刪了吧,以前用到此方法的地方會報錯,不刪吧,又怕新來的程序員調用此方法。這時候我們就可以用上注解了,在JavaSE5中內置了三種注解定義在java.lang包中,裏麵有一個@Deprecated(棄用的意思)的注解,我們隻要在sayHello()方法上加上@Deprecated注解就能滿足我們的需求了。

       代碼演示:

       沒加注解的代碼


       加了注解的代碼



六、注解的應用

       1.使用注解

       當在程序中調用一個過時的方法時,Eclipse工具會在過時的方法上麵畫上一跳橫線,如圖所示。


       當你沒有用開發工具編譯上麵的方法,而是用cmd命令行,javac命令編譯上麵的方法時,會是什麼樣的呢?如下圖所示


      然而有些人,就喜歡用過時的方法,並且不希望被提示,那又怎麼做呢?這時我們可以在方法前麵加一個特殊的標識(也就是注解)代碼如下:

    @SuppressWarnings("deprecation")//SuppressWarnings壓製警告
    public static void main(String[] args) throws Exception{
        // TODO Auto-generated method stub
        System.runFinalizersOnExit(true);
    }

    當你在方法前麵加上@SuppressWarnings("deprecation ")時,在Eclipse中那條橫線還是存在的,但是你用cmd命令行javac編譯,就不會有提示了,如圖

   

    2.自定義注解

       注解就是一個特殊的類,當你要用一類時,不是不要讓這個類先存在呀,答案坑定是要的,所以用注解時,也要先有注解。一個注解將會和3個類有聯係,下麵給張圖幫助理解

        注解的語法有點類似於接口,隻是在接口前麵加了一個“@”符號,public @interface ItcastAnnocation {}

      


定義一個注解

public @interface ItcastAnnocation {

}

在一個類中使用注解

@ItcastAnnocation

public class AnnotationTest {

    /**
     * @param args
     */
    public static void main(String[] args) throws Exception{
        // TODO Auto-generated method stub
        //System.runFinalizersOnExit(true);
        //sayHello();
        /**
         *判斷注解ItcastAnnocation在不在AnnotationTest類上麵
         *方法isAnnotationPresent幫助文檔的介紹是: 如果指定類型的注釋存在於此元素上,則返回 true,否則返回 false。
         */
        if(AnnotationTest.class.isAnnotationPresent(ItcastAnnocation.class)){
            System.out.println(1);
            ItcastAnnocation  itcastAnnocation =( ItcastAnnocation)AnnotationTest.class.getAnnotation(ItcastAnnocation.class);
            System.out.println(itcastAnnocation);
        }
    }

運行結果:控製台不輸入任何東西。要想讓控製台打印出1和其他的東西,就要先介紹元注解----元注解就是,注解的注解(在注解類身上加的注解)。



然後將注解類改成下麵這樣

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
/**
 * Retention:保留
 * Retention:保留;Policy:政策
 * RUNTIME:我的理解是運行時
 */
@Retention(RetentionPolicy.RUNTIME)//這理解為:把ItcastAnnocation注解保留到運行時
public @interface ItcastAnnocation {

}

輸出結果:

1
@cn.itcast.day2.ItcastAnnocation()



這裏麵有這樣一些情況:

情況一:一個類被Javac編譯成class文件的時候,Javac可能會把這個類上麵的注解給去掉,所以當你用class文件的時候就找不到類上麵的注解。

情況二:假如Javac沒有去掉注解,程序用class文件的時候,會用類加載器把class文件給調到內存裏麵去,(class文件裏麵的東西不是字節碼,隻有類加載器把class文件裏麵的東西做安全檢查等各方麵的處理,人後再加載到內存中,這時候的class才是字節碼),類加載器也可能會把class文件裏麵的注解給去掉。

所以說注解的生命周期有3個階段分別是:java源文件、class文件、內存中的字節碼。

@Retention(RetentionPolicy.RUNTIME)中的RetentionPolicy有三種取值RetentionPolicy.SOURCE、RetentionPolicy.CLASS和RetentionPolicy.RUNTIME分別對應上麵所說的三個生命周期。默認值在class階段。

思考題:@Override、@SuppressWarnings、@Deprecated這三個分別在什麼階段?

先看代碼:

/**
 * Retention:保留
 * Retention:保留;Policy:政策
 * RUNTIME:我的理解是運行時
 * Target:目標
 * Element:元素
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)//這理解為:把ItcastAnnocation注解保留到運行時
public @interface ItcastAnnocation {

}

下麵介紹一個@Target(ElementType.PACKAGE),他也是元注解,他是用來限定注解的位置的,上麵是把注解限定在方法上的。所以出現了在使用時如下圖的錯誤,下圖是放在類上的

要定義在多個地方都能用要這樣寫@Target({ElementType.FIELD,ElementType.METHOD,ElementType.PACKAGE}),{}數組的簡寫。

比class高一級的抽象是Type,接口、枚舉、注解它們像類,單嚴格的說又不是,但它們都表示一個java的類型,class也屬於java的類型。所以在@Target()裏麵要表示類的話得用ElementType.TYPT來表示,TYPE也是jdk1.5才出現的



七、注解的高級運用

      一、注解的屬性

          1、注解的屬性與作用

              打個比方說:假如你是一個傳智播客的學生,為了讓別人知道,我就會給你貼上一個標簽(在代碼中就是注解),但是光貼上標簽是不夠的,因為我想知道你是哪個班的,但是我無法知道啊,這時候怎麼辦呢?我們可以用注解的屬性來解決這個問題。

          2、給注解添加屬性代碼演示3

添加注解屬性

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
 * Retention:保留
 * Retention:保留;Policy:政策
 * RUNTIME:我的理解是運行時
 * Target:目標
 * Element:元素
 */
@Target({ElementType.TYPE,ElementType.METHOD,})
@Retention(RetentionPolicy.RUNTIME)//這理解為:把ItcastAnnocation注解保留到運行時
public @interface ItcastAnnocation {
    String color() default "blue";//設置color屬性的默認值為blue
    String value();
    int[] arrayAtt();//為注解添加數組類型的屬性
    EnumLight light();//為注解添加枚舉類型的屬性
    MyMetaAnnotation test1() ;//為注解添加注解類型的屬性
    Class test2();//為注解添加原始類型的屬性
}

使用注解屬性

package cn.itcast.day2;
@ItcastAnnocation(color="red",value="abc",arrayAtt=3, light = EnumLight.red, test1 = @MyMetaAnnotation("bgv"),test2=int.class)
public class AnnotationTest {

    /**
     * @param args
     */
//    @ItcastAnnocation("abc",arrayAtt = { 0 })
    public static void main(String[] args) throws Exception{
        /**
         *判斷注解ItcastAnnocation在不在AnnotationTest類上麵
         *方法isAnnotationPresent幫助文檔的介紹是: 如果指定類型的注釋存在於此元素上,則返回 true,否則返回 false。
         */
        if(AnnotationTest.class.isAnnotationPresent(ItcastAnnocation.class)){
            ItcastAnnocation  itcastAnnocation =( ItcastAnnocation)AnnotationTest.class.getAnnotation(ItcastAnnocation.class);
            System.out.println(itcastAnnocation.color());//打印屬性color的值
            System.out.println(itcastAnnocation.value());//打印屬性value的值
            System.out.println(itcastAnnocation.arrayAtt().length);//打印數組屬性的長度
            /**
             * 打印數組屬性中的每個元素
             */
            for (Object obj : itcastAnnocation.arrayAtt()) {
                System.out.println(obj);
            }
            System.out.println(itcastAnnocation.light());//打印枚舉屬性的值
            System.out.println(itcastAnnocation.test1().value());//打印出注解屬性類型為注解的注解,它的屬性。
            System.out.println(itcastAnnocation.test2());//打印原始類型的屬性
        }
    }
}

上麵用到的2個類

1.

public enum EnumLight {
    red,green,yellow;
}

2.
/**
 * 用來測試注解屬性是注解類型用的
 * @author JSON
 *
 */
public @interface MyMetaAnnotation {
    String value();
}


關於注解屬性不帶‘=’符號的寫法

@SuppressWarnings("deprecation"),如果隻有一個屬性的值需要你賦值,那麼你就可以不寫等號了。

---------------------------------------------------------------------------------------------------------------------------------------

public @interface ItcastAnnocation {
    String color() default "blue";//default:用法是給color屬性設置默認值為blue
    String value();
}

運行打印輸出:

red
abc
1
3
red
bgv
int



注意的地方:

注解屬性方法可以沒有任何參數

注解屬性方法不能有任何類型的參數

注解屬性方法聲明不能有一個throws子句


最後更新:2017-04-03 14:54:15

  上一篇:go c/c++ 變量生存期
  下一篇:go 求先序遍曆