首頁  >  文章  >  Java  >  深入理解Java:註解(Annotation)基本概念

深入理解Java:註解(Annotation)基本概念

巴扎黑
巴扎黑原創
2017-06-26 09:18:321226瀏覽

什麼是註解(Annotation):

  Annotation(註解)就是Java提供了一種元程式中的元素關聯任何資訊和著任何元資料(metadata)的途徑和方法。 Annotion(註解)是一個接口,程式可以透過反射來取得指定程式元素的Annotion對象,然後透過Annotion物件來取得註解裡面的元資料。

  Annotation(註解)是JDK5.0及以後版本引進的。它可以用於創建文檔,追蹤程式碼中的依賴性,甚至執行基本編譯時檢查。從某些方面來看,annotation就像修飾符一樣被使用,並應用於套件、類別 類型、建構方法、方法、成員變數、參數、本地變數的宣告。這些資訊被儲存在Annotation的「name=value」結構對中。

  Annotation的成員在Annotation類型中以無參數的方法的形式被宣告。其方法名和回傳值定義了該成員的名字和類型。在此有一個特定的預設語法:允許聲明任何Annotation成員的預設值:一個Annotation可以將name=value對作為沒有定義預設值的Annotation成員的值,當然也可以使用name=value對來覆蓋其它成員默認值。這一點有些近似類別的繼承特性,父類別的建構子可以作為子類別的預設建構函數,但是也可以被子類別覆蓋。

  Annotation能被用來為某個程式元素(類別、方法、成員變數等)關聯任何的資訊。要注意的是,這裡有一個基本的規則:Annotation不能影響程式碼的執行,無論增加、刪除 Annotation,程式碼都一致的執行。另外,儘管一些annotation透過java的反射api方法在運行時被訪問,而java語言解釋器在工作時忽略了這些annotation。正是由於java虛擬機忽略了Annotation,導致了annotation類型在程式碼中是「不起作用」的; 只有透過某種配套的工具才會對annotation類型中的資訊進行存取和處理。本文將涵蓋標準的Annotation和meta-annotation類型,陪伴這些annotation類型的工具就是java編譯器(當然要以某種特殊的方式處理它們)。


什麼是metadata(元資料):

  元資料從metadata一詞譯來,就是「關於資料的資料」的意思。
  元資料的功能作用很多,例如:你可能用過Javadoc的註解自動產生文件。這就是元資料功能的一種。總的來說,元資料可以用來建立文檔,追蹤程式碼的依賴性,執行編譯時格式檢查,取代現有的設定檔。如果要對於元資料的作用進行分類,目前還沒有明確的定義,不過我們可以根據它所起的作用,大致可分為三類: 
    1. 編寫文件:透過程式碼中標識的元資料生成文件
    2. 程式碼分析:透過程式碼裡識別的元資料對程式碼進行分析
    3. 編譯檢查:透過程式碼中識別的元資料讓編譯器能實現基本的編譯檢查Java##  ##  在Java中元資料以標籤的形式存在於Java程式碼中,元資料標籤的存在並不影響程式碼的編譯和執行,它只是被用來產生其它的檔案或針在執行時知道被執行程式碼的描述資訊。
  綜上所述:
    第一,元資料以標籤的形式存在於Java程式碼中。
    第二,元資料所描述的資訊是型別安全的,即元資料內部的欄位都是有明確類型的。
    第三,元資料需要編譯器以外的工具額外的處理用來產生其它的程式部件。
    第四,元資料可以只存在於Java原始碼級別,也可以存在於編譯之後的Class檔案內部。


 Annotation和Annotation類型:

  Annotation:

  Annotation使用了在java5.0所帶來的新語法,它的行為十分類似public、final這樣的修飾符。每個Annotation具有一個名字和成員個數>=0。每個Annotation的成員具有被稱為name=value對的名字和值(就像javabean一樣),name=value裝載了Annotation的資訊。

  Annotation類型:

  Annotation類型定義了Annotation的名字、類型、成員預設值。一個Annotation類型可以說是一個特殊的java接口,它的成員變數是受限的,而宣告Annotation類型時需要使用新語法。當我們透過java反射api來存取Annotation時,返回值將是一個實現了該 annotation類型介面的對象,透過存取這個對像我們能方便的存取到其Annotation成員。後面的章節將提到在java5.0的 java.lang包裡包含的3個標準Annotation類型。


註解的分類:

  根據註解參數的個數,我們可以將註解分為三類:
    1.標記註解:一個沒有成員定義的Annotation類型被稱為標記註解。這種Annotation類型僅使用自身的存在與否來為我們提供資訊。如後面的系統註解@Override;
    2.單值註解
    3.完整註解

  根據註解使用方法和用途,我們可以將Annotation

#  根據註解使用方法和用途,我們可以將Annotation

#     JDK內建系統註解
    2.元註解

    3.自訂註解

## 系統內建符號標準註解:

  註解的語法比較簡單,除了@內建符號的使用比較簡單,除了@@外,他基本上與Java固有的語法一致,JavaSE中內建三個標準註解,定義在java.lang中:
    @Override:用於修飾此方法覆蓋了父類的方法;

    @Deprecated:用於修飾已經過時的方法;

    @SuppressWarnnings:用來通知java編譯器禁止特定的編譯警告。


  下面我們依序看看三個內建標準註解的作用和使用情境。

   @Override,限定重寫父類別方法:

  @Override 是一個標記註解類型,它被用作標註方法。它說明了被標註的方法重載了父類別的方法,起到了斷言的作用。如果我們使用了這種Annotation在一個沒有覆蓋父類別方法的方法時,java編譯器會以一個編譯錯誤來警告。這個annotaton常常在我們試圖覆蓋父類別方法而確又寫錯了方法名時發揮威力。使用方法極為簡單:使用此annotation時只要在被修飾的方法前面加上@Override即可。下面的程式碼是使用@Override修飾一個企圖重載父類別的displayName()方法,而又有拼字錯誤的實例:
深入理解Java:註解(Annotation)基本概念
public class Fruit {

    public void displayName(){
        System.out.println("水果的名字是:*****");
    }
}

class Orange extends Fruit {
    @Override
    public void displayName(){
        System.out.println("水果的名字是:桔子");
    }
}

class Apple extends Fruit {
    @Override
    public void displayname(){
        System.out.println("水果的名字是:苹果");
    }
}
深入理解Java:註解(Annotation)基本概念

  Orange 类编译不会有任何问题,Apple 类在编译的时候会提示相应的错误。@Override注解只能用于方法,不能用于其他程序元素。

#@Deprecated,標記已過時:

  同樣Deprecated也是一個標記註解。當一個類型或類型成員使用@Deprecated修飾的話,編譯器將不鼓勵使用這個被標註的程式元素。而且這種修飾具有一定的「延續性」:如果我們在程式碼中透過繼承或覆蓋的方式使用了這個過時的類型或成員,雖然繼承或覆蓋後的類型或成員並不是被聲明為@Deprecated,但編譯器仍然要警報。

  值得注意,@Deprecated這個annotation類型和javadoc中的@deprecated這個tag是有區別的:前者是java編譯器識別的,而後者是被javadoc工具所識別用來生成文檔(包含程序成員為什麼已經過時、它應該如何被禁止或替代的描述)。

  在java5.0,java編譯器仍然像其從前版本那樣尋找@deprecated這個javadoc tag,並使用它們產生警告訊息。但是這種狀況將在後續版本中改變,我們應在現在就開始使用@Deprecated來修飾過時的方法而不是 @deprecated javadoc tag。

  下面一段程式中使用了@Deprecated註解標示方法過期,同時在方法註解中用@deprecated tag 標示該方法已經過時,程式碼如下:
深入理解Java:註解(Annotation)基本概念
#
 class AppleService {
    public void displayName(){
        System.out.println("水果的名字是:苹果");
    }
    
    /**
     * @deprecated 该方法已经过期,不推荐使用
     */
    @Deprecated
    public void showTaste(){
        System.out.println("水果的苹果的口感是:脆甜");
    }
    
    public void showTaste(int typeId){
        if(typeId==1){
            System.out.println("水果的苹果的口感是:酸涩");
        }
        else if(typeId==2){
            System.out.println("水果的苹果的口感是:绵甜");
        }
        else{
            System.out.println("水果的苹果的口感是:脆甜");
        }
    }
}

public class FruitRun {

    /**
     * @param args
     */
    public static void main(String[] args) {
        Apple apple=new Apple();
        apple.displayName();    
        
        AppleService appleService=new AppleService();
        appleService.showTaste();
        appleService.showTaste(0);
        appleService.showTaste(2);
    }

}
深入理解Java:註解(Annotation)基本概念
######

  AppleService类的showTaste() 方法被@Deprecated标注为过时方法,在FruitRun类中使用的时候,编译器会给出该方法已过期,不推荐使用的提示。


SuppressWarnnings,抑制编译器警告:

  @SuppressWarnings 被用于有选择的关闭编译器对类、方法、成员变量、变量初始化的警告。在java5.0,sun提供的javac编译器为我们提供了-Xlint选项来使编译器对合法的程序代码提出警告,此种警告从某种程度上代表了程序错误。例如当我们使用一个generic collection类而又没有提供它的类型时,编译器将提示出"unchecked warning"的警告。通常当这种情况发生时,我们就需要查找引起警告的代码。如果它真的表示错误,我们就需要纠正它。例如如果警告信息表明我们代码中的switch语句没有覆盖所有可能的case,那么我们就应增加一个默认的case来避免这种警告。
  有时我们无法避免这种警告,例如,我们使用必须和非generic的旧代码交互的generic collection类时,我们不能避免这个unchecked warning。此时@SuppressWarning就要派上用场了,在调用的方法前增加@SuppressWarnings修饰,告诉编译器停止对此方法的警告。
  SuppressWarning不是一个标记注解。它有一个类型为String[]的成员,这个成员的值为被禁止的警告名。对于javac编译器来讲,被-Xlint选项有效的警告 名也同样对@SuppressWarings有效,同时编译器忽略掉无法识别的警告名。
  annotation语法允许在annotation名后跟括号,括号中是使用逗号分割的name=value对用于为annotation的成员赋值。实例如下:

深入理解Java:註解(Annotation)基本概念
public class FruitService {
    
    @SuppressWarnings(value={ "rawtypes", "unchecked" })
    public static  List<fruit> getFruitList(){
        List<fruit> fruitList=new ArrayList();
        return fruitList;
    }
    
    @SuppressWarnings({ "rawtypes", "unchecked" })
    public static  List<fruit> getFruit(){
        List<fruit> fruitList=new ArrayList();
        return fruitList;
    }

    @SuppressWarnings("unused")
    public static void main(String[] args){
        List<string> strList=new ArrayList<string>();
    }
}</string></string></fruit></fruit></fruit></fruit>
深入理解Java:註解(Annotation)基本概念

  在这个例子中SuppressWarnings annotation类型只定义了一个单一的成员,所以只有一个简单的value={...}作为name=value对。又由于成员值是一个数组,故使用大括号来声明数组值。注意:我们可以在下面的情况中缩写annotation:当annotation只有单一成员,并成员命名为"value="。这时可以省去"value="。比如将上面方法getFruit()的SuppressWarnings annotation就是缩写的。

   SuppressWarnings注解的常见参数值的简单说明:

    1.deprecation:使用了不赞成使用的类或方法时的警告;
    2.unchecked:执行了未检查的转换时的警告,例如当使用集合时没有用泛型 (Generics) 来指定集合保存的类型; 
    3.fallthrough:当 Switch 程序块直接通往下一种情况而没有 Break 时的警告;
    4.path:在类路径、源文件路径等中有不存在的路径时的警告; 
    5.serial:当在可序列化的类上缺少 serialVersionUID 定义时的警告; 
    6.finally:任何 finally 子句不能正常完成时的警告; 

    7.all:关于以上所有情况的警告。

学习Java的同学注意了!!!
学习过程中遇到什么问题或者想获取学习资源的话,欢迎加入Java学习交流群:159610322   我们一起学Java!

以上是深入理解Java:註解(Annotation)基本概念的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn