Java註解-後設資料、註解分類、內建註解和自定義註解

樂位元組發表於2019-07-26

大家好,我是樂位元組的小樂,上次說過了Java多型的6大特性|樂位元組,接下來我們來看看Java程式設計裡的註解。

Java註解-後設資料、註解分類、內建註解和自定義註解

Java註解有以下幾個知識點:

  • 後設資料
  • 註解的分類
  • 內建註解
  • 自定義註解
  • 註解處理器
  • Servlet3.0

本文先介紹前面4個知識點:後設資料、註解的分類、內建註解、自定義註解。


一、註解簡介

註解是Java 1.5引入的,目前已被廣泛應用於各種Java框架,如Hibernate,Jersey,

Spring。註解相當於是一種嵌入在程式中的後設資料,可以使用註解解析工具或編譯器對

其進行解析,也可以指定註解在編譯期或執行期有效。


在註解誕生之前,程式的後設資料存在的形式僅限於java註釋或javadoc,但註解可以提

供更多功能,它不僅包含後設資料,還能作用於執行期,註解解析器能夠使用註解決定處

理流程。


Annotation(註解)就是Java提供了一種元程式中的元素關聯任何資訊和任何後設資料

(metadata)的途徑和方法。Annotation是一個介面,程式可以通過反射來獲取指定

程式元素的Annotation物件,然後通過Annotation物件來獲取註解裡面的後設資料。

註解API非常強大,被廣泛應用於各種Java框架,如Spring,Hibernate,JUnit。

二、 後設資料metadata

後設資料從metadata一詞譯來,就是“關於資料的資料”的意思,即描述資料的結構資訊。後設資料的功能作用有很多,比如:你可能用過Javadoc的註釋自動生成文件。這就是後設資料功能的一種。總的來說,後設資料可以用來建立文件,跟蹤程式碼的依賴性,執行編譯時格式檢查,代替已有的配置檔案。

在Java中後設資料以標籤的形式存在於Java程式碼中,後設資料標籤的存在並不影響程式程式碼的編譯和執行,被用來生成其它的檔案或只在執行時知道被執行程式碼的描述資訊。

其作用如下:

①生成文件:這是最常見的,也是java 最早提供的註解。常用的有@param @return 等;

② 跟蹤程式碼依賴性,實現替代配置檔案功能。常見的是spring 2.5 開始的基於註解配置。作用就是減少配置。現在的框架基本都使用了這種配置來減少配置檔案的數量。;

③在編譯時進行格式檢查。如@override 放在方法前,如果你這個方法並不是覆蓋了超類方法,則編譯時就能檢查出。

三、 註解的分類

根據註解引數的個數:

1)、標記註解:一個沒有成員定義的Annotation型別被稱為標記註解。

2)、單值註解:只有一個值

3)、完整註解:擁有多個值

根據註解使用方法和用途:

1)、JDK內建系統註解

2)、元註解

3)、自定義註解

四、 內建註解

JavaSE中內建三個標準註解,定義在java.lang中:

@Override

限定重寫父類方法,若想要重寫父類的一個方法時,需要使用該註解告知編譯器我們正在重寫一個方法。如此一來,當父類的方法被刪除或修改了,編譯器會提示錯誤資訊;或者該方法不是重寫也會提示錯誤。

public interface Car {
	void run();
}
class QQ implements Car{
	@Override
	public void run() {}
}
class Bmw implements Car{
	@Override
	void run() {}
}複製程式碼


QQ 類編譯不會有任何問題,Bmw類在編譯的時候會提示相應的錯誤。父類中省略了public abstract修飾符。@Override註解只能用於方法,不能用於其他程式元素。

@Deprecated

標記已過時,當我們想要讓編譯器知道一個方法已經被棄用(deprecate)時,應該使用這個註解。Java推薦在javadoc中提供資訊,告知使用者為什麼這個方法被棄用了,以及替代方法是什麼;

/**
 *  Deprecated -->該方法過時(有更好的解決方案)
 * @author Administrator
 */
public class TestDeprecated {
	@Deprecated
	public int test(){
		System.out.println("TestDeprecated.test()");
		return 0;
	}
	public void test(int a){
		System.out.println("TestDeprecated.test(int)");
	}
}複製程式碼

3. @SuppressWarnings

抑制編譯器警告,該註解僅僅告知編譯器,忽略它們產生了特殊警告。如:在java泛型中使用原始型別。其保持性策略(retention policy)是SOURCE,在編譯器中將被丟棄。

/**
 * SuppressWarnings 壓制警告
 * @author Administrator
 */
public class TestSuppressWarnings {
	public static void main(String[] args) {
		@SuppressWarnings("unused")
		List<String> list =new ArrayList<String>();
	}
	@SuppressWarnings("rawtypes") //沒有定義範型
	public static List test(){
		return new ArrayList();
	}
}複製程式碼

五、 自定義註解

1、簡單入門

@interface:用來宣告一個註解。註解類裡的每一個方法實際上是宣告瞭一個配置引數。方法的名稱就是引數的名稱,返回值型別就是引數的型別。可以通過default來宣告引數的預設值。

@interface Simple{
//這裡定義了一個空的註解,它能幹什麼呢?我也不知道,但他能用。後面有補充
}複製程式碼


2、元註解

元註解的作用就是負責註解其他註解。Java5.0定義了4個標準的meta-annotation型別,它們被用來提供對其它 annotation型別作說明。Java5.0定義的元註解有四個,

這些型別和它們所支援的類在java.lang.annotation包中可以找到。

@Target

用於描述註解的使用範圍(即:被描述的註解可以用在什麼地方)。表示支援註解的程式元素的種類,一些可能的值有TYPE, METHOD, CONSTRUCTOR, FIELD等等。如果Target元註解不存在,那麼該註解就可以使用在任何程式元素之上。

取值(ElementType)有:

 1.CONSTRUCTOR:用於描述構造器
 2.FIELD:用於描述域
 3.LOCAL_VARIABLE:用於描述區域性變數
 4.METHOD:用於描述方法
 5.PACKAGE:用於描述包
 6.PARAMETER:用於描述引數
 7.TYPE:用於描述類、介面(包括註解型別) 或enum宣告

此時在空註解中加入@Target元註解如:

//此註解只能用在方法上
@Target(ElementType.METHOD) 
@interface TestMethod {}複製程式碼

@Retention

表示需要在什麼級別儲存該註釋資訊,用於描述註解的生命週期(即:被描述的注在什麼範圍內有效)表示註解型別保留時間的長短。

取值(RetentionPoicy)有:

1.SOURCE:在原始檔中有效(即原始檔保留)
2.CLASS:在class檔案中有效(即class保留)
3.RUNTIME:在執行時有效(即執行時保留)

此時在上述註解中加入@Retention元註解如:

// 此註解可以用於註解類、介面(包括註解型別) 或enum宣告
@Target(ElementType.TYPE) 
//該註解執行時有效。註解處理器可以通過反射,獲取到該註解的屬性值,從而去做一些執行時的邏輯處理
@Retention(RetentionPolicy.RUNTIME)
@interface TestRn{
}複製程式碼


@Documented

表示使用該註解的元素應被javadoc或類似工具文件化,它應用於型別宣告,型別宣告的註解會影響客戶端對註解元素的使用。如果一個型別宣告新增了Documented註解,那麼它的註解會成為被註解元素的公共API的一部分,@Documented是一個標記註解。

//可以被例如javadoc此類的工具文件化
@Documented
@interface TestDoc{	
}複製程式碼

@Inherited

表示一個註解型別會被自動繼承,如果使用者在類宣告的時候查詢註解型別,同時類宣告中也沒有這個型別的註解,那麼註解型別會自動查詢該類的父類,這個過程將會不停地重複,直到該型別的註解被找到為止,或是到達類結構的頂層(Object)。

//被子類繼承的註解
@Inherited
@interface TestInheri{}複製程式碼


3、深入自定義註解

使用@interface自定義註解時,自動繼承了java.lang.annotation.Annotation介面,由編譯程式自動完成其他細節。在定義註解時,不能繼承其他的註解或介面。

⑴定義註解格式:

@interface用來宣告一個註解,其中的每一個方法實際上是宣告瞭一個配置引數。方法的名稱就是引數的名稱,返回值型別就是引數的型別(返回值型別只能是基本型別、Class、String、enum)。可以通過default來宣告引數的預設值。

public @interface 註解名{定義體s}

⑵註解引數(即方法)

註解裡面的每一個方法實際上就是宣告瞭一個配置引數,其規則如下:

①修飾符

只能用public或預設(default)這兩個訪問權修飾 ,預設為default

②型別

註解引數只支援以下資料型別:

基本資料型別(int,float,boolean,byte,double,char,long,short);

String型別;

Class型別;

enum型別;

Annotation型別;

以上所有型別的陣列

③命名

對取名沒有要求,如果只有一個引數成員,最好把引數名稱設為"value",後加小括號。

④引數

註解中的方法不能存在引數

⑤預設值

可以包含預設值,使用default來宣告預設值。

⑶例項如下

/*
 * 碼農定義註解
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface Programmer{
	String value() default "馬雲";
}
/**
 * 碼農型別註解
 * @author peida
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface ProgrammerType {
    /**
     * 型別列舉  程式猿 射雞師
     */
    public enum CoderType{MONKEYS,LION,CHOOK};
    /**
     * 顏色屬性
     */
    CoderType type() default CoderType.MONKEYS;
}
/**
 * 碼農製造廠
 * @author Administrator
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@interface ProgrammerProductor {
    /**
     * 廠家編號
     * @return
     */
    public int id() default -1;
    /**
     * 廠家名稱
     * @return
     */
    public String name() default "shsxt"; 
    /**
     * 廠家地址
     * @return
     */
    public String address() default "上海";
}
/**
 * 註解使用
*/
class Coder{
		@Programmer("老裴")
	    private String coderName;
		@ProgrammerType(type=CoderType.MONKEYS)
	    private String coderType;
		@ProgrammerProductor(id=1,name="程式猿樂園",address="榮樂東路")
	    private String coderProductor;
		public String getCoderName() {
			return coderName;
		}
		public void setCoderName(String coderName) {
			this.coderName = coderName;
		}
		public String getCoderType() {
			return coderType;
		}
		public void setCoderType(String coderType) {
			this.coderType = coderType;
		}
		public String getCoderProductor() {
			return coderProductor;
		}
		public void setCoderProductor(String coderProductor) {
			this.coderProductor = coderProductor;
		}	
}

樂位元組原創,轉載請註明出處複製程式碼


相關文章