枚举对象注释_如何以及何时使用枚举和注释
枚舉對象注釋
本文是我們名為“ 高級Java ”的學(xué)院課程的一部分。
本課程旨在幫助您最有效地使用Java。 它討論了高級主題,包括對象創(chuàng)建,并發(fā),序列化,反射等。 它將指導(dǎo)您完成Java掌握的旅程! 在這里查看 !
目錄
1.簡介 2.枚舉作為特殊類 3.枚舉和實(shí)例字段 4.枚舉和接口 5.枚舉和泛型 6.便捷的枚舉方法 7.專門的集合:EnumSet和EnumMap 8.何時使用枚舉 9.注釋作為特殊接口 10.注釋和保留政策 11.注釋和元素類型 12.注釋和繼承 13.可重復(fù)的注釋 14.注釋處理器 15.約定上的注釋和配置 16.何時使用注釋 17.下一步是什么 18.下載源代碼1.簡介
在本教程的這一部分中,我們將介紹Java 5版本中引入到語言中的另外兩個重要功能以及泛型:枚舉(或枚舉)和注釋。 枚舉可以被視為一種特殊的類,而注解可以被視為一種特殊的接口。
枚舉的概念很簡單,但是非常方便:它表示一組固定的,恒定的值。 實(shí)際上,這意味著通常使用枚舉來設(shè)計具有恒定可能狀態(tài)集的概念。 例如,星期幾就是枚舉的一個很好的例子:它們僅限于星期一,星期二,星期三,星期四,星期五,星期六和星期日。
另一方面,注釋是一種特殊的元數(shù)據(jù),可以與Java語言的不同元素和構(gòu)造相關(guān)聯(lián)。 有趣的是,注釋對消除Java生態(tài)系統(tǒng)中大多數(shù)地方使用的樣板XML描述符起了很大的作用。 他們介紹了一種新的,類型安全且健壯的配置和自定義技術(shù)方法。
2.枚舉作為特殊類
在將枚舉引入Java語言之前,在Java中建模固定值集的常規(guī)方法是聲明一些常量。 例如:
public class DaysOfTheWeekConstants {public static final int MONDAY = 0;public static final int TUESDAY = 1;public static final int WEDNESDAY = 2;public static final int THURSDAY = 3;public static final int FRIDAY = 4;public static final int SATURDAY = 5;public static final int SUNDAY = 6; }盡管這種方法行之有效,但遠(yuǎn)非理想的解決方案。 主要是因?yàn)槌A勘旧碇皇莍nt類型的值,并且代碼中應(yīng)期望這些常量的每個位置(而不是任意的int值)都應(yīng)始終明確記錄并聲明。 從語義上講,它不是該概念的類型安全表示形式,如以下方法所示。
public boolean isWeekend( int day ) {return( day == SATURDAY || day == SUNDAY ); }從邏輯角度來看,day參數(shù)應(yīng)具有在DaysOfTheWeekConstants類中聲明的值之一。 但是,如果不編寫其他文檔(然后由其他人閱讀),則無法猜測。 對于Java編譯器,像isWeekend (100)這樣的調(diào)用看起來是絕對正確的,不會引起任何問題。
枚舉在這里進(jìn)行了救援。 枚舉允許用類型化的值替換常量,并在各處使用這些類型。 讓我們使用枚舉重寫上面的解決方案。
public enum DaysOfTheWeek {MONDAY,TUESDAY,WEDNESDAY,THURSDAY,FRIDAY,SATURDAY,SUNDAY }更改的是class成為enum ,并且可能的值在枚舉定義中列出。 但是,區(qū)別在于每個值都是在其聲明的枚舉類的實(shí)例(在我們的示例中為DaysOfTheWeek )。 這樣,無論何時使用枚舉,Java編譯器都可以進(jìn)行類型檢查。 例如:
public boolean isWeekend( DaysOfTheWeek day ) {return( day == SATURDAY || day == SUNDAY ); }請注意,枚舉中大寫命名方案的使用只是一個約定,沒有什么真正阻止您不這樣做的。
3.枚舉和實(shí)例字段
枚舉是專門的類,因此是可擴(kuò)展的。 這意味著它們可以具有實(shí)例字段,構(gòu)造函數(shù)和方法(盡管唯一的限制是不能聲明默認(rèn)的no-args構(gòu)造函數(shù),并且所有構(gòu)造函數(shù)都必須是private )。 讓我們使用實(shí)例字段和構(gòu)造函數(shù)將屬性isWeekend添加到一周的每一天。
public enum DaysOfTheWeekFields {MONDAY( false ),TUESDAY( false ),WEDNESDAY( false ),THURSDAY( false ),FRIDAY( false ),SATURDAY( true ),SUNDAY( true );private final boolean isWeekend;private DaysOfTheWeekFields( final boolean isWeekend ) {this.isWeekend = isWeekend;}public boolean isWeekend() {return isWeekend;} }正如我們所看到的,枚舉的值只是構(gòu)造函數(shù)調(diào)用,簡化了不需要new關(guān)鍵字的情況。 isWeekend()屬性可用于檢測該值代表工作日還是工作日結(jié)束。 例如:
public boolean isWeekend( DaysOfTheWeek day ) {return day.isWeekend(); }實(shí)例字段是Java枚舉中極為有用的功能。 它們經(jīng)常用于使用常規(guī)的類聲明規(guī)則將一些其他詳細(xì)信息與每個值相關(guān)聯(lián)。
4.枚舉和接口
另一個有趣的功能(又一次證實(shí)了枚舉只是專門的類)是它們可以實(shí)現(xiàn)接口(但是,由于后面的枚舉和泛型部分中說明的原因,枚舉不能擴(kuò)展任何其他類)。 例如,讓我們介紹接口DayOfWeek 。
interface DayOfWeek {boolean isWeekend(); }并使用接口實(shí)現(xiàn)而不是常規(guī)實(shí)例字段重寫上一部分中的示例。
public enum DaysOfTheWeekInterfaces implements DayOfWeek {MONDAY() {@Overridepublic boolean isWeekend() {return false;}},TUESDAY() {@Overridepublic boolean isWeekend() {return false;}},WEDNESDAY() {@Overridepublic boolean isWeekend() {return false;}},THURSDAY() {@Overridepublic boolean isWeekend() {return false;}},FRIDAY() {@Overridepublic boolean isWeekend() {return false;}},SATURDAY() {@Overridepublic boolean isWeekend() {return true;}},SUNDAY() {@Overridepublic boolean isWeekend() {return true;}}; }我們實(shí)現(xiàn)接口的方式有些冗長,但是可以通過將實(shí)例字段和接口組合在一起來使其更好。 例如:
public enum DaysOfTheWeekFieldsInterfaces implements DayOfWeek {MONDAY( false ),TUESDAY( false ),WEDNESDAY( false ),THURSDAY( false ),FRIDAY( false ),SATURDAY( true ),SUNDAY( true );private final boolean isWeekend;private DaysOfTheWeekFieldsInterfaces( final boolean isWeekend ) {this.isWeekend = isWeekend;}@Overridepublic boolean isWeekend() {return isWeekend;} }通過支持實(shí)例字段和接口,枚舉可以以更加面向?qū)ο蟮姆绞绞褂?#xff0c;從而帶來某種程度的抽象依賴。
5.枚舉和泛型
盡管乍看之下看不到它,但是Java中的枚舉和泛型之間存在聯(lián)系。 Java中的每個枚舉都是自動從通用Enum< T >類繼承的,其中T是枚舉類型本身。 Java編譯器在編譯時代表開發(fā)人員進(jìn)行此轉(zhuǎn)換,將枚舉聲明public enum DaysOfTheWeek為如下所示:
public class DaysOfTheWeek extends Enum< DaysOfTheWeek > {// Other declarations here }它還說明了為什么枚舉可以實(shí)現(xiàn)接口但不能擴(kuò)展其他類的原因:它們隱式擴(kuò)展了Enum< T >并且如本教程第2部分所知, 使用所有對象通用的方法 ,Java不支持多重繼承。
每個枚舉都擴(kuò)展Enum< T >的事實(shí)允許定義將枚舉類型的實(shí)例作為參數(shù)或類型參數(shù)的通用類,接口和方法。 例如:
public< T extends Enum < ? > > void performAction( final T instance ) {// Perform some action here }在上面的方法聲明中,類型T被約束為任何枚舉的實(shí)例,Java編譯器將對此進(jìn)行驗(yàn)證。
6.便捷的枚舉方法
Enum< T >類提供了兩個有用的方法,每個枚舉實(shí)例都會自動繼承這些方法。
| 方法 | 描述 |
| String name() | 返回此枚舉常量的名稱,該名稱與在其枚舉聲明中聲明的完全相同。 |
| int ordinal() | 返回此枚舉常量的序數(shù)(其在枚舉聲明中的位置,其中初始常量的序數(shù)為零)。 |
表格1
此外,Java編譯器會為它遇到的每個枚舉類型自動生成兩個更有用的static方法(讓我們將特定的枚舉類型稱為T )。
| 方法 | 描述 |
| T[] values() | 返回枚舉T的所有聲明的枚舉常量。 |
| T valueOf(String name) | 返回具有指定名稱的枚舉常量T |
表2
由于這些方法的存在和艱苦的編譯器工作,在代碼中使用枚舉還有另一個好處:它們可以在switch/case語句中使用。 例如:
public void performAction( DaysOfTheWeek instance ) {switch( instance ) {case MONDAY:// Do somethingbreak;case TUESDAY:// Do somethingbreak;// Other enum constants here} }7.專門的集合:EnumSet和EnumMap
與所有其他類一樣,枚舉的實(shí)例可以與標(biāo)準(zhǔn)Java集合庫一起使用。 但是,某些收集類型已經(jīng)專門針對枚舉進(jìn)行了優(yōu)化,并且在大多數(shù)情況下建議使用它們來代替通用的對應(yīng)類型。
我們將研究兩種專門的集合類型: EnumSet< T >和EnumMap< T, ? > EnumMap< T, ? > 。 兩者都很容易使用,我們將從EnumSet< T > 。
EnumSet< T >是優(yōu)化的常規(guī)集,可以有效地存儲枚舉。 有趣的是, EnumSet< T >無法使用構(gòu)造函數(shù)實(shí)例化,而是提供了許多有用的工廠方法(我們在本教程的第1部分“ 如何創(chuàng)建和銷毀對象”中介紹了工廠模式)。
例如, allOf工廠方法創(chuàng)建EnumSet< T >的實(shí)例,該實(shí)例包含所涉及的枚舉類型的所有枚舉常量:
final Set< DaysOfTheWeek > enumSetAll = EnumSet.allOf( DaysOfTheWeek.class );因此, noneOf工廠方法為有問題的枚舉類型創(chuàng)建一個空的EnumSet< T >的實(shí)例:
final Set< DaysOfTheWeek > enumSetNone = EnumSet.noneOf( DaysOfTheWeek.class );另外,也可以指定哪些枚舉所討論的枚舉類型的常量應(yīng)當(dāng)納入EnumSet< T >使用of工廠方法:
final Set< DaysOfTheWeek > enumSetSome = EnumSet.of(DaysOfTheWeek.SUNDAY,DaysOfTheWeek.SATURDAY );EnumMap< T, ? > EnumMap< T, ? >非常接近于常規(guī)映射,不同之處在于其鍵可以是所討論枚舉類型的枚舉常量。 例如:
final Map< DaysOfTheWeek, String > enumMap = new EnumMap<>( DaysOfTheWeek.class ); enumMap.put( DaysOfTheWeek.MONDAY, "Lundi" ); enumMap.put( DaysOfTheWeek.TUESDAY, "Mardi" );請注意,作為大多數(shù)集合實(shí)現(xiàn), EnumSet< T >和EnumMap< T, ? > EnumMap< T, ? >不是線程安全的,并且不能在多線程環(huán)境中按原樣使用(我們將在本教程的第9部分“ 并發(fā)最佳實(shí)踐”中討論線程安全和同步)。
8.何時使用枚舉
由于Java 5發(fā)布枚舉是使用固定的常量集表示和撥號的唯一首選和推薦方法。 它們不僅是強(qiáng)類型的,而且是可擴(kuò)展的,并得到任何現(xiàn)代庫或框架的支持。
9.注釋作為特殊接口
如前所述,注釋是用于將元數(shù)據(jù)與Java語言的不同元素相關(guān)聯(lián)的語法糖。
注釋本身對所注釋的元素沒有任何直接影響。 但是,根據(jù)注釋及其定義方式的不同,Java編譯器可能會使用它們(一個很好的例子是@Override注釋,我們在本教程的第3部分“ 如何設(shè)計類和接口 ),注釋處理器(更多詳細(xì)信息將在“ 注釋處理器”部分中)以及運(yùn)行時使用反射和其他自省技術(shù)的代碼(有關(guān)本教程的第11部分中的更多內(nèi)容, 反射和動態(tài)語言支持 )。
讓我們看一下最簡單的注釋聲明:
public @interface SimpleAnnotation { }The @interface keyword introduces new annotation type. That is why annotations could be treated as specialized interfaces. Annotations may declare the attributes with or without default values, for example: public @interface SimpleAnnotationWithAttributes {String name();int order() default 0; }如果注釋聲明的屬性沒有默認(rèn)值,則應(yīng)在應(yīng)用注釋的所有位置提供該屬性。 例如:
@SimpleAnnotationWithAttributes( name = "new annotation" )按照慣例,如果注釋具有帶有名稱value的屬性,并且它是唯一需要指定的屬性,則可以省略屬性的名稱,例如:
public @interface SimpleAnnotationWithValue {String value(); }It could be used like this:@SimpleAnnotationWithValue( "new annotation" )在某些用例中,有兩個限制使使用注釋不太方便。 首先,注釋不支持任何繼承:一個注釋不能擴(kuò)展另一個注釋。 其次,不可能使用new運(yùn)算符以編程方式創(chuàng)建注釋的實(shí)例(我們將參考本教程的第11部分“ 反射和動態(tài)語言支持”中的一些變通方法)。 第三,注釋只能聲明基本類型的屬性,即String或Class< ? > Class< ? >這些的類型和數(shù)組。 注釋中不允許聲明任何方法或構(gòu)造函數(shù)。
10.注釋和保留政策
每個注釋都有一個非常重要的特性,稱為保留策略 ,這是一個枚舉(類型為RetentionPolicy ),其中包含有關(guān)如何保留注釋的策略集。 可以將其設(shè)置為以下值之一。
| 政策 | 描述 |
| CLASS | 批注由編譯器記錄在類文件中,但在運(yùn)行時VM無需保留批注 |
| RUNTIME | 注釋由編譯器記錄在類文件中,并在運(yùn)行時由VM保留,因此可以通過反射方式讀取它們。 |
| SOURCE | 批注將被編譯器丟棄。 |
表3
保留策略對注釋何時可用于處理至關(guān)重要。 可以使用@Retention批注設(shè)置保留策略。 例如:
import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy;@Retention( RetentionPolicy.RUNTIME ) public @interface AnnotationWithRetention { }將注釋保留策略設(shè)置為RUNTIME將保證它在編譯過程和正在運(yùn)行的應(yīng)用程序中的存在。
11.注釋和元素類型
每個注釋必須具有的另一個特征是可以應(yīng)用的元素類型。 與保留策略類似,它被定義為帶有可能元素類型集的枚舉( ElementType )。
| 元素類型 | 描述 |
| ANNOTATION_TYPE | 注釋類型聲明 |
| CONSTRUCTOR | 構(gòu)造函數(shù)聲明 |
| FIELD | 字段聲明(包括枚舉常量) |
| LOCAL_VARIABLE | 局部變量聲明 |
| METHOD | 方法聲明 |
| PACKAGE | 包裹申報 |
| PARAMETER | 參數(shù)聲明 |
| TYPE | 類,接口(包括注釋類型)或枚舉聲明 |
表4
除了上述描述的元素外,Java 8還引入了兩種可以應(yīng)用注釋的新元素類型。
| 元素類型 | 描述 |
| TYPE_PARAMETER | 類型參數(shù)聲明 |
| TYPE_USE | 使用類型 |
表5
與保留策略相反,注釋可以使用@Target注釋聲明可以與之關(guān)聯(lián)的多種元素類型。 例如:
import java.lang.annotation.ElementType; import java.lang.annotation.Target;@Target( { ElementType.FIELD, ElementType.METHOD } ) public @interface AnnotationWithTarget { }通常,要創(chuàng)建的所有注釋都應(yīng)同時指定保留策略和元素類型,以便使用。
12.注釋和繼承
在Java中,聲明注釋和繼承之間存在重要的關(guān)系。 默認(rèn)情況下,子類不繼承在父類上聲明的注釋。 但是,有一種方法可以使用@Inherited批注在類層次結(jié)構(gòu)中傳播特定批注。 例如:
@Target( { ElementType.TYPE } ) @Retention( RetentionPolicy.RUNTIME ) @Inherited @interface InheritableAnnotation { }@InheritableAnnotation public class Parent { }public class Child extends Parent { }在此示例中,在Parent類上聲明的@InheritableAnnotation注釋也將由Child類繼承。
13.可重復(fù)的注釋
在Java 8之前的時代,與注釋相關(guān)的另一個限制尚未討論:同一注釋只能在同一位置出現(xiàn)一次,不能重復(fù)多次。 Java 8通過提供對可重復(fù)注釋的支持來減輕這種限制。 例如:
@Target( ElementType.METHOD ) @Retention( RetentionPolicy.RUNTIME ) public @interface RepeatableAnnotations {RepeatableAnnotation[] value(); }@Target( ElementType.METHOD ) @Retention( RetentionPolicy.RUNTIME ) @Repeatable( RepeatableAnnotations.class ) public @interface RepeatableAnnotation {String value(); }; @RepeatableAnnotation( "repeatition 1" ) @RepeatableAnnotation( "repeatition 2" ) public void performAction() {// Some code here }盡管在Java 8中,可重復(fù)注釋功能需要做一些工作才能使注釋可重復(fù)(使用@Repeatable ),但最終結(jié)果還是值得的:更干凈,更緊湊的帶注釋的代碼。
14.注釋處理器
Java編譯器支持一種稱為注解處理器的特殊類型的插件(使用–processor命令行參數(shù)),可以在編譯階段處理注解。 注釋處理器可以分析注釋的用法(執(zhí)行靜態(tài)代碼分析),創(chuàng)建其他Java源文件或資源(依次可以對其進(jìn)行編譯和處理)或?qū)ψ⑨尩拇a進(jìn)行更改。
保留策略 (請參閱注釋和保留策略 )通過指示編譯器哪些注釋應(yīng)可用于注釋處理器進(jìn)行處理而發(fā)揮了關(guān)鍵作用。
注解處理器被廣泛使用,但是要編寫注解處理器,它需要Java編譯器如何工作以及編譯過程本身的一些知識。
15.約定上的注釋和配置
約定優(yōu)于配置是一種軟件設(shè)計范例,旨在簡化開發(fā)人員遵循一組簡單規(guī)則(或約定)的開發(fā)過程。 例如,某些MVC (模型-視圖-控制器)框架遵循約定將控制器放置在“ controller”文件夾(或程序包)中。 另一個示例是ORM (對象關(guān)系映射器)框架,該框架通常遵循約定以在“模型”文件夾(或程序包)中查找類,并從相應(yīng)的類派生關(guān)系表名稱。
另一方面,注釋為基于顯式配置的不同設(shè)計范例打開了道路。 考慮以上示例, @Controller Controller批注可以將任何類顯式標(biāo)記為controller,而@Entity可以引用關(guān)系數(shù)據(jù)庫表。 好處還來自以下事實(shí):注釋是可擴(kuò)展的,可能具有其他屬性,并且僅限于特定的元素類型。 Java編譯器強(qiáng)加了對注釋的不正確使用,并在早期(在編譯階段)揭示了配置錯誤的問題。
16.何時使用注釋
注釋幾乎無處不在:Java標(biāo)準(zhǔn)庫有很多注釋,大多數(shù)每個Java規(guī)范也都包含注釋。 每當(dāng)您需要將其他元數(shù)據(jù)與代碼相關(guān)聯(lián)時,批注便是直接簡單的方法。
有趣的是,Java社區(qū)正在不斷努力開發(fā)通用的語義概念,并使幾種Java技術(shù)之間的注釋標(biāo)準(zhǔn)化(有關(guān)更多信息,請參閱JSR-250規(guī)范 )。 目前,標(biāo)準(zhǔn)Java庫包含以下注釋。
| 注解 | 描述 |
| @Deprecated | 指示已標(biāo)記的元素已棄用,不應(yīng)再使用。 每當(dāng)程序使用帶有此批注的方法,類或字段時,編譯器都會生成警告。 |
| @Override | 提示編譯器該元素旨在替代超類中聲明的元素。 |
| @SuppressWarnings | 指示編譯器禁止以其他方式生成的特定警告。 |
| @SafeVarargs | 當(dāng)應(yīng)用于方法或構(gòu)造函數(shù)時,斷言該代碼不會對其varargs參數(shù)執(zhí)行潛在的不安全操作。 使用此批注類型時,將禁止使用與varargs有關(guān)的未經(jīng)檢查的警告(有關(guān)varargs的更多詳細(xì)信息將在本教程的第6部分“ 如何有效地編寫方法”中進(jìn)行介紹 )。 |
| @Retention | 指定如何保??留標(biāo)記的注釋。 |
| @Target | 指定可以將標(biāo)記的注釋應(yīng)用于哪種Java元素。 |
| @Documented | 指示無論何時使用指定的注釋,都應(yīng)使用Javadoc工具記錄這些元素(默認(rèn)情況下,Javadoc中不包含注釋)。 |
| @Inherited | 指示可以從超類繼承注釋類型(有關(guān)更多詳細(xì)信息,請參閱注釋和繼承部分)。 |
表6
Java 8發(fā)行版還添加了一些新的注釋。
| 注解 | 描述 |
| @FunctionalInterface | 指示類型聲明旨在用作Java語言規(guī)范所定義的功能接口(有關(guān)功能接口的更多詳細(xì)信息,將在本教程的第3部分“ 如何設(shè)計類和接口”中進(jìn)行介紹 )。 |
| @Repeatable | 指示標(biāo)記的注釋可以多次應(yīng)用于同一聲明或類型使用(有關(guān)更多詳細(xì)信息,請參閱“可重復(fù)注釋”部分)。 |
表7
17.下一步是什么
在本節(jié)中,我們介紹了用于表示固定常量集的枚舉(或枚舉),以及使用元數(shù)據(jù)裝飾Java代碼元素的注釋。 盡管沒有什么聯(lián)系,但這兩個概念在Java中已被廣泛使用。 盡管在本教程的下一部分中,我們將繼續(xù)研究如何有效地編寫方法,但注釋通常會成為大多數(shù)討論的一部分。
18.下載源代碼
這是關(guān)于如何設(shè)計類和接口的課程。 您可以在此處下載源代碼: advanced-java-part-5
翻譯自: https://www.javacodegeeks.com/2015/09/how-and-when-to-use-enums-and-annotations.html
枚舉對象注釋
總結(jié)
以上是生活随笔為你收集整理的枚举对象注释_如何以及何时使用枚举和注释的全部內(nèi)容,希望文章能夠幫你解決所遇到的問題。
- 上一篇: hibernate与jpa_将JPA H
- 下一篇: 苹果11手机参数是什么