注解
注解(一種元數據形式)提供有關不屬于程序本身的程序的數據,注解對它們注解的代碼的操作沒有直接影響。
注解有許多用途,其中包括:
編譯器的信息 — 編譯器可以使用注解來檢測錯誤或抑制警告。
編譯時和部署時處理 — 軟件工具可以處理注解信息以生成代碼、XML文件等。
運行時處理 — 可以在運行時檢查某些注解。
本課程介紹了可以使用注解的位置,以及如何應用注解,Java平臺標準版(Java SE API)中提供了哪些預定義注解類型,類型注解如何與可插拔類型系統結合使用來編寫具有更強類型檢查的代碼,以及如何實現重復注解。
注解基礎知識 注解的格式在最簡單的形式中,注解如下所示:
@Entity
符號字符(@)向編譯器指示后面的內容是注解,在以下示例中,注解的名稱為Override:
@Override void mySuperMethod() { ... }
注解可以包含元素,這些元素可以是命名的,也可以是未命名的,這些元素的值如下:
@Author( name = "Benjamin Franklin", date = "3/27/2003" ) class MyClass() { ... }
或:
@SuppressWarnings(value = "unchecked") void myMethod() { ... }
如果只有一個名為value的元素,則可以省略該名稱,如:
@SuppressWarnings("unchecked") void myMethod() { ... }
如果注解沒有元素,則可以省略括號,如前面的@Override示例所示。
也可以在同一聲明上使用多個注解:
@Author(name = "Jane Doe") @EBook class MyClass { ... }
如果注解具有相同的類型,則稱為重復注解:
@Author(name = "Jane Doe") @Author(name = "John Smith") class MyClass { ... }
從Java SE 8發行版開始,支持重復注解,有關更多信息,請參閱重復注解。
注解類型可以是Java SE API的java.lang或java.lang.annotation包中定義的類型之一,在前面的示例中,Override和SuppressWarnings是預定義的Java注解,也可以定義自己的注解類型,上一個示例中的Author和Ebook注解是自定義注解類型。
可以使用注解的位置注解可以應用于聲明:類、字段、方法和其他程序元素的聲明,當在聲明中使用時,按照慣例,每個注解通常出現在它自己的行上。
從Java SE 8發行版開始,注解也可以應用于類型的使用,這里有些例子:
類實例創建表達式:
new @Interned MyObject();
輸入:
myString = (@NonNull String) str;
implements子句:
class UnmodifiableListimplements @Readonly List<@Readonly T> { ... }
拋出的異常聲明:
void monitorTemperature() throws @Critical TemperatureException { ... }
這種形式的注解稱為類型注解,有關更多信息,請參閱類型注解和可插拔類型系統。
聲明注解類型許多注解替換代碼中的注釋。
假設一個軟件組通常在每個類的開頭都帶有注釋,這些注釋提供了重要的信息:
public class Generation3List extends Generation2List { // Author: John Doe // Date: 3/17/2002 // Current revision: 6 // Last modified: 4/12/2004 // By: Jane Doe // Reviewers: Alice, Bill, Cindy // class code goes here }
要使用注解添加相同的元數據,必須先定義注解類型,這樣做的語法是:
@interface ClassPreamble { String author(); String date(); int currentRevision() default 1; String lastModified() default "N/A"; String lastModifiedBy() default "N/A"; // Note use of array String[] reviewers(); }
注解類型定義類似于接口定義,其中關鍵字interface前面帶有at符號(@)(@ = AT,如在注解類型中),注解類型是一種接口形式,將在后面的課程中介紹,目前,你不需要了解接口。
前一個注解定義的主體包含注解類型元素聲明,它看起來很像方法,請注意,他們可以定義可選的默認值。
定義注解類型后,你可以使用該類型的注解,并填入值,如下所示:
@ClassPreamble ( author = "John Doe", date = "3/17/2002", currentRevision = 6, lastModified = "4/12/2004", lastModifiedBy = "Jane Doe", // Note array notation reviewers = {"Alice", "Bob", "Cindy"} ) public class Generation3List extends Generation2List { // class code goes here }
注意:要使@ClassPreamble中的信息出現在Javadoc生成的文檔中,必須使用@Documented注解來注解@ClassPreamble定義:
// import this to use @Documented import java.lang.annotation.*; @Documented @interface ClassPreamble { // Annotation element definitions }預定義的注解類型
Java SE API中預定義了一組注解類型,某些注解類型用于Java編譯器使用,有些注解類型應用于其他注解。
Java語言使用的注解類型java.lang中定義的預定義注解類型是@Deprecated、@Override和@SuppressWarnings。
@Deprecated:@Deprecated注解表示標記已棄用和不應該再使用的元素,只要程序使用帶有@Deprecated注解的方法、類或字段,編譯器就會生成警告。當棄用元素時,也應使用Javadoc @deprecated標記對其進行記錄,如以下示例所示。在Javadoc注釋和注解中使用at符號(@)并非巧合:它們在概念上是相關的,另請注意,Javadoc標記以小寫d開頭,注解以大寫D開頭。
// Javadoc comment follows /** * @deprecated * explanation of why it was deprecated */ @Deprecated static void deprecatedMethod() { }
@Override:@Override注解通知編譯器該元素旨在覆蓋超類中聲明的元素,將在接口和繼承中討論重寫方法。
// mark method as a superclass method // that has been overridden @Override int overriddenMethod() { }
雖然在重寫方法時不需要使用此注解,但它有助于防止出錯,如果使用@Override標記的方法無法正確覆蓋其某個超類中的方法,則編譯器會生成錯誤。
@SuppressWarnings:@SuppressWarnings注解告訴編譯器抑制它將生成的特定警告,在以下示例中,使用了棄用的方法,編譯器通常會生成警告,但是,在這種情況下,注解會導致警告被抑制。
// use a deprecated method and tell // compiler not to generate a warning @SuppressWarnings("deprecation") void useDeprecatedMethod() { // deprecation warning // - suppressed objectOne.deprecatedMethod(); }
每個編譯器警告都屬于一個類別,Java語言規范列出了兩個類別:deprecation和unchecked,當在泛型出現之前編寫的遺留代碼接口時,可能會發生unchecked警告,要禁止多種類別的警告,請使用以下語法:
@SuppressWarnings({"unchecked", "deprecation"})
@SafeVarargs:@SafeVarargs注解在應用于方法或構造函數時斷言代碼不對其varargs參數執行可能不安全的操作,使用此注解類型時,與varargs使用相關的未經檢查的警告被抑制。
@FunctionalInterface:Java SE 8中引入的@FunctionalInterface注解,表示類型聲明旨在成為Java語言規范定義的功能接口。
應用于其他注解的注解應用于其他注解的注解稱為元注解,java.lang.annotation中定義了幾種元注解類型。
@Retention:@Retention注解指定標記的注解的存儲方式:
RetentionPolicy.SOURCE — 標記的注解僅保留在源級別中,并被編譯器忽略。
RetentionPolicy.CLASS — 標記的注解在編譯時由編譯器保留,但Java虛擬機(JVM)會忽略。
RetentionPolicy.RUNTIME — 標記的注解由JVM保留,因此運行時環境可以使用它。
@Documented:@Documented注解表明,無論何時使用指定的注解,都應使用Javadoc工具記錄這些元素(默認情況下,注解不包含在Javadoc中),有關更多信息,請參閱Javadoc工具頁面。
@Target:@Target注解標記另一個注解,以限制可以應用注解的Java元素類型,目標注解指定以下元素類型之一作為其值:
ElementType.ANNOTATION_TYPE可以應用于注解類型。
ElementType.CONSTRUCTOR可以應用于構造函數。
ElementType.FIELD可以應用于字段或屬性。
ElementType.LOCAL_VARIABLE可以應用于局部變量。
ElementType.METHOD可以應用于方法級注解。
ElementType.PACKAGE可以應用于包聲明。
ElementType.PARAMETER可以應用于方法的參數。
ElementType.TYPE可以應用于類的任何元素。
@Inherited:@Inherited注解表明注解類型可以從超類繼承(默認情況下不是這樣),當用戶查詢注解類型并且該類沒有此類型的注解時,將查詢類的超類以獲取注解類型,此注解僅適用于類聲明。
@Repeatable:Java SE 8中引入的@Repeatable注解表明標記的注解可以多次應用于相同的聲明或類型使用,有關更多信息,請參閱重復注解。
類型注解和可插拔類型系統在Java SE 8發行版之前,注解只能應用于聲明,從Java SE 8發行版開始,注解也可以應用于任何類型的使用,這意味著可以在任何使用類型的地方使用注解。使用類型的一些示例包括類實例創建表達式(new)、類型轉換、implements子句和throws子句,這種注解形式稱為類型注解,注解基礎知識中提供了幾個示例。
創建類型注解是為了支持改進的Java程序分析,以確保更強的類型檢查,Java SE 8版本不提供類型檢查框架,但它允許你編寫(或下載)類型檢查框架,該框架實現為與Java編譯器結合使用的一個或多個可插拔模塊。
例如,你希望確保程序中的特定變量永遠不會分配給null,你想避免觸發NullPointerException,你可以編寫自定義插件來檢查此問題,然后,你將修改代碼以注解該特定變量,表明它永遠不會被賦值為null,變量聲明可能如下所示:
@NonNull String str;
當你編譯代碼(包括命令行中的NonNull模塊)時,編譯器會在檢測到潛在問題時輸出警告,允許你修改代碼以避免錯誤,在更正代碼以移除所有警告后,程序運行時不會發生此特定錯誤。
你可以使用多個類型檢查模塊,其中每個模塊檢查不同類型的錯誤,通過這種方式,你可以在Java類型系統的基礎上構建,在你希望的時間和位置添加特定的檢查。
通過明智地使用類型注解和可插拔類型檢查器,你可以編寫更強大且更不容易出錯的代碼。
在許多情況下,你不必編寫自己的類型檢查模塊,有第三方為你完成了這項工作,例如,你可能希望利用華盛頓大學創建的Checker Framework,該框架包括NonNull模塊、正則表達式模塊和互斥鎖模塊,有關更多信息,請參閱Checker Framework。
重復注解在某些情況下,你希望將相同的注解應用于聲明或類型用途,從Java SE 8發行版開始,重復注解使你可以執行此操作。
例如,你正在編寫代碼以使用計時器服務,該服務使你能夠在給定時間或某個計劃上運行方法,類似于UNIX cron服務,現在你要設置一個計時器來運行一個方法doPeriodicCleanup,在該月的最后一天和每個星期五晚上11點運行,要設置要運行的計時器,請創建一個@Schedule注解并將其應用于doPeriodicCleanup方法兩次,第一次使用指定月份的最后一天,第二次使用指定星期五晚上11點,如下面的代碼示例所示:
@Schedule(dayOfMonth="last") @Schedule(dayOfWeek="Fri", hour="23") public void doPeriodicCleanup() { ... }
前面的示例將注解應用于方法,你可以在使用標準注解的任何位置重復注解,例如,你有一個用于處理未授權訪問異常的類,你可以使用一個@Alert注解為管理者注解該類,為管理員注解另一個注解:
@Alert(role="Manager") @Alert(role="Administrator") public class UnauthorizedAccessException extends SecurityException { ... }
出于兼容性原因,重復注解存儲在由Java編譯器自動生成的容器注解中,為了使編譯器執行此操作,代碼中需要兩個聲明。
第1步:聲明可重復的注解類型注解類型必須使用@Repeatable元注解進行標記,以下示例定義自定義@Schedule可重復注解類型:
@Repeatable(Schedules.class) public @interface Schedule { String dayOfMonth() default "first"; String dayOfWeek() default "Mon"; int hour() default 12; }
@Repeatable元注解的值(在括號中)是Java編譯器生成的用于存儲重復注解的容器注解的類型,在此示例中,包含注解類型是Schedules,因此重復@Schedule注解存儲在@Schedules注解中。
將相同的注解應用于聲明而不首先聲明它是可重復的,這會導致編譯時錯誤。
第2步:聲明包含注解類型包含注解類型必須具有帶數組類型的value元素,數組類型的組件類型必須是可重復的注解類型,包含注解類型的Schedules的聲明如下:
public @interface Schedules { Schedule[] value(); }檢索注解
Reflection API中有幾種可用于檢索注解的方法,返回單個注解的方法(例如AnnotatedElement.getAnnotation(Class
設計注解類型時,必須考慮該類型注解的基數,現在可以使用注解零次、一次,或者,如果注解的類型標記為@Repeatable,則不止一次,通過使用@Target元注解,還可以限制注解類型的使用位置。例如,你可以創建只能在方法和字段上使用的可重復注解類型,仔細設計注解類型非常重要,以確保使用注解的程序員發現它盡可能靈活和強大。
上一篇:枚舉類型 下一篇:接口文章版權歸作者所有,未經允許請勿轉載,若此文章存在違規行為,您可以聯系管理員刪除。
轉載請注明本文地址:http://specialneedsforspecialkids.com/yun/72468.html
Java? 教程 Java教程是為JDK 8編寫的,本頁面中描述的示例和實踐沒有利用在后續版本中引入的改進。 Java教程是希望使用Java編程語言創建應用程序的程序員的實用指南,其中包括數百個完整的工作示例和數十個課程,相關課程組被組織成教程。 覆蓋基礎知識的路徑 這些教程以書籍的形式提供,如Java教程,第六版,前往Amazon.com購買。 入門 介紹Java技術和安裝Java開發軟件并使用...
摘要:通過前面四篇的學習,我們已經在本地安裝了一個數據庫,并且通過一個簡單的應用的單元測試,插入了幾條記錄到中,并通過查看到了插入的數據。讀操作最終將會使用我們在最簡單的入門教程之三使用代碼往里插入數據里介紹的方法,即通過注入的實例完成對的操作。 通過前面四篇的學習,我們已經在本地安裝了一個MongoDB數據庫,并且通過一個簡單的Spring boot應用的單元測試,插入了幾條記錄到Mong...
摘要:通過前面四篇的學習,我們已經在本地安裝了一個數據庫,并且通過一個簡單的應用的單元測試,插入了幾條記錄到中,并通過查看到了插入的數據。讀操作最終將會使用我們在最簡單的入門教程之三使用代碼往里插入數據里介紹的方法,即通過注入的實例完成對的操作。 通過前面四篇的學習,我們已經在本地安裝了一個MongoDB數據庫,并且通過一個簡單的Spring boot應用的單元測試,插入了幾條記錄到Mong...
摘要:典型示例以下結構是比較推薦的組織方式,所有的類和其他都在之下。應用主類,該類直接位于下。默認情況下,的應用主類會自動掃描以及所有子包下的所有類來進行初始化。 Spring Boot框架本身并沒有對工程結構有特別的要求,但是按照最佳實踐的工程結構可以幫助我們減少可能會遇見的坑,尤其是Spring包掃描機制的存在,如果您使用最佳實踐的工程結構,可以免去不少特殊的配置工作。 典型示例 以下結...
閱讀 1683·2023-04-25 20:16
閱讀 3836·2021-10-09 09:54
閱讀 2696·2021-09-04 16:40
閱讀 2517·2019-08-30 15:55
閱讀 829·2019-08-29 12:37
閱讀 2733·2019-08-26 13:55
閱讀 2903·2019-08-26 11:42
閱讀 3144·2019-08-23 18:26