【Java】枚舉類和注解


一、枚舉類的使用

1. 枚舉類的說明:

  1. 枚舉類的理解:類的對象只有有限個,確定的。我們稱此類為枚舉類

  2. 當需要定義一組常量時,強烈建議使用枚舉類

  3. 枚舉類的實現:
    • JDK 5.0以前需要自定義
    • JDK 5.0后新增enum關鍵字用於定義枚舉類
  4. 如果枚舉類中只一個對象,則可以作為單例模式的實現方式。

  5. 枚舉類的屬性:
    枚舉類對象的屬性不應允許被改動,所以應該使用 private final 修飾 枚舉類的使用 private final修飾的屬性應該在構造器中為其賦值 若枚舉類顯式的定義了帶參數的構造器,則在列出枚舉值時也必須對應的傳入參數

2. 如何自定義枚舉類?

步驟:

  1. 私有化構造器,保證不能在類的外部創建其對象;
  2. 在類的內部創建枚舉類的實例。聲明為:public static final

    1. 因為要通過類來調取使用,靜態在類里面了,不動了,所以需要 public static
    2. 又不允許改變,所以為 final。

    這個枚舉類里面有好幾個對象,每個對象相當於是一個常量
    如果這個類只有一個對象,那么可以看成是一個單例模式

  3. 對象如果有實例變量,應該聲明為private final,並在構造器中初始化;

代碼示例:

//自定義枚舉類
class Season{
    //1.聲明Season對象的屬性:private final修飾
    private final String seasonName;
    private final String seasonDesc;

    //2.私化類的構造器,並給對象屬性賦值
    private Season(String seasonName,String seasonDesc){
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }

    //3.提供當前枚舉類的多個對象:public static final的
    public static final Season SPRING = new Season("春天","春暖花開");
    public static final Season SUMMER = new Season("夏天","夏日炎炎");
    public static final Season AUTUMN = new Season("秋天","秋高氣爽");
    public static final Season WINTER = new Season("冬天","冰天雪地");

    //4.其他訴求1:獲取枚舉類對象的屬性
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }
    //4.其他訴求1:提供toString()
    @Override
    public String toString() {
        return "Season{" +
            "seasonName='" + seasonName + '\'' +
            ", seasonDesc='" + seasonDesc + '\'' +
            '}';
    }
}

3. JDK 5.0 新增使用enum定義枚舉類。

使用說明:

  • 使用enum定義的枚舉類默認繼承了java.lang.Enum類,因此不能再繼承其他類

  • 枚舉類的構造器只能使用private權限修飾符

  • 枚舉類的所有實例必須在枚舉類中顯式列出(“,”分隔“;”結尾)。列出的實例系統會自動添加public static final修飾

  • 必須在枚舉類的第一行聲明枚舉類對象

代碼示例:

//使用enum關鍵字枚舉類
enum Season1 {
    //1.提供當前枚舉類的對象,多個對象之間用","隔開,末尾對象";"結束
    SPRING("春天","春暖花開"),
    SUMMER("夏天","夏日炎炎"),
    AUTUMN("秋天","秋高氣爽"),
    WINTER("冬天","冰天雪地");

    //2.聲明Season對象的屬性:private final修飾
    private final String seasonName;
    private final String seasonDesc;

    //2.私化類的構造器,並給對象屬性賦值

    private Season1(String seasonName,String seasonDesc){
        this.seasonName = seasonName;
        this.seasonDesc = seasonDesc;
    }

    //4.其他訴求1:獲取枚舉類對象的屬性
    public String getSeasonName() {
        return seasonName;
    }

    public String getSeasonDesc() {
        return seasonDesc;
    }

}

Enum類的常用方法:

  1. values()方法:返回枚舉類型的對象數組。該方法可以很方便地遍歷所有的枚舉值。

  2. valueOf(String str):可以把一個字符串轉為對應的枚舉類對象。要求字符串必須是枚舉類對象的“名字”.如不是,會有運行時異常IllegalArgumentException

  3. toString():返回當前枚舉類對象常量的名稱(可重寫自定義)

  4. name():返回當前枚舉類對象常量的名稱(final不可重寫)

  5. ordinal():返回枚舉值在枚舉元素數組中的下標。

代碼示例:

Season1 summer = Season1.SUMMER;
//toString():返回枚舉類對象的名稱
System.out.println(summer.toString());

//        System.out.println(Season1.class.getSuperclass());
System.out.println("****************");
//values():返回所的枚舉類對象構成的數組
Season1[] values = Season1.values();
for(int i = 0;i < values.length;i++){
    System.out.println(values[i]);
}
System.out.println("****************");
Thread.State[] values1 = Thread.State.values();
for (int i = 0; i < values1.length; i++) {
    System.out.println(values1[i]);
}

//valueOf(String objName):返回枚舉類中對象名是objName的對象。
Season1 winter = Season1.valueOf("WINTER");
//如果沒objName的枚舉類對象,則拋異常:IllegalArgumentException
//        Season1 winter = Season1.valueOf("WINTER1");
System.out.println(winter);

用Enum類定義的枚舉類對象分別實現接口:

使用說明:

  1. 和普通Java類一樣,枚舉類可以實現一個或多個接口
  2. 若每個枚舉值在調用實現的接口方法呈現相同的行為方式,則只要統一實現該方法即可。
  3. 若需要每個枚舉值在調用實現的接口方法呈現出不同的行為方式,則可以讓每個枚舉值分別來實現該方法

代碼示例:

interface Info{
    void show();
}

//使用enum關鍵字枚舉類
enum Season1 implements Info{
    //1.提供當前枚舉類的對象,多個對象之間用","隔開,末尾對象";"結束
    SPRING("春天","春暖花開"){
        @Override
        public void show() {
            System.out.println("春天在哪里?");
        }
    },
    SUMMER("夏天","夏日炎炎"){
        @Override
        public void show() {
            System.out.println("寧夏");
        }
    },
    AUTUMN("秋天","秋高氣爽"){
        @Override
        public void show() {
            System.out.println("秋天不回來");
        }
    },
    WINTER("冬天","冰天雪地"){
        @Override
        public void show() {
            System.out.println("大約在冬季");
        }
    };
}

二、注解的使用

1. 注解的理解

  1. jdk 5.0 新增的功能

  2. Annotation 其實就是代碼里的特殊標記, 這些標記可以在編譯, 類加載, 運行時被讀取, 並執行相應的處理。通過使用 Annotation,程序員可以在不改變原邏輯的情況下, 在源文件中嵌入一些補充信息。

  3. Annotation可以像修飾符一樣使用,可以用來修飾包、類、構造器、方法、成員變量、參數、局部變量的聲明,這些信息被保存在Annotation的“name = value”對中。

  4. 在JavaSE中,注解的使用目的比較簡單,例如標記過時的功能,忽略警告等。在JavaEE/Android 中注解占據了更重要的角色,例如用來配置應用程序的任何切面,代替JavaEE舊版中所遺留的繁冗 代碼和XML配置等。

  5. 框架 = 注解 + 反射機制 + 設計模式

2. 注解的使用示例

使用 Annotation時要在其前面增加@符號,並把該 Annotation當成個修飾符使用。用於修飾它支持的程序元素

示例一:生成文檔相關的注解

  • @author標明開發該類模塊的作者,多個作者之間使用,分割
  • @version標明該類模塊的版本
  • @see參考轉向,也就是相關主題
  • @since從哪個版本開始增加的
  • @param對方法中某參數的說明,如果沒有參數就不能寫
  • @return對方法返回值的說明,如果方法的返回值類型是void就不能寫
  • @exception對方法可能拋出的異常進行說明,如果方法沒有用 throws顯式拋出的異常就不能寫

其中

  • @param@return@exception這三個標記都是只用於方法的。
  • @param的格式要求:@param形參名形參類型形參說明
  • @return的格式要求:@return返回值類型返回值說明
  • @exception的格式要求:@exception異常類型異常說明
  • @param@exception可以並列多個

代碼示例:

/**
 * @author nemo
 * @project_name JavaSenior
 * @package_name com.nemo.java
 * @create 2020-04-26 10:58
 */
public class AnnotationTest {
    /**
     *程序的主方法
     * @param args 傳入命令行參數
     */
    public static void main(String[] args) {

    }

    /**
     * 求圓形面積
     * @param radius 所求面積的半徑
     * @return 面積值
     */
    public static double getArea(double radius){
        return Math.PI * radius * radius;
    }
}

示例二:在編譯時進行格式檢查(JDK內置的個基本注解)

  • @Override: 限定重寫父類方法, 該注解只能用於方法
  • @Deprecated: 用於表示所修飾的元素(類, 方法等)已過時。通常是因為所修飾的結構危險或存在更好的選擇
  • @SuppressWarnings: 抑制編譯器警告

代碼示例:

public class AnnotationTest{
    public static void mian (String [] args){
        @SuppressWarning("unused")
        int a = 0;
    }
    @Deprecated
    public void print(){
        System.out.print("過時的方法");
    }
    @Override
    public String toString(){
        return "重寫的toString方法";
    }
}

示例三:跟蹤代碼依賴性,實現替代配置文件功能

在使用Spring框架時會大量用到注解驅動開發。

3. 如何自定義注解

參照@SuppressWarnings定義

  1. 注解聲明為:@interface
  2. 內部定義成員,通常使用無參無異常方法value()表示

    如果成員只有一個,那么這個成員必須取名為value(),使用時可以忽略成員名和賦值號(=)。
    理解:為什么要使用無參無異常方法呢,我認為那是因為,如果使用變量來進行存儲的話,在接口中,屬性變量會變為常量,占取空間;
    而我們這個注解又不是那么的需要這個屬性(占空間),只是在屬性調用到的時候起作用。
    需要在調用的時候才起作用,那肯定是方法比較符合條件了。

    記憶:這個注解的使用方式比較類似於方法,如@Params(...),所以里面的注解實現也都用方法value()表示。

  3. 可以指定成員的默認值,使用default定義
  4. 如果自定義注解沒成員,表明是一個標識作用。

說明:

  • 如果注解有成員,在使用注解時,需要指明成員的值。
  • 自定義注解必須配上注解的信息處理流程(使用反射)才意義。
  • 自定義注解通過都會指明兩個元注解:@Retention@Target

代碼舉例:

@Inherited
@Repeatable(MyAnnotations.class)
@Retention(RetentionPolicy.RUNTIME)
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE,TYPE_PARAMETER,TYPE_USE})
public @interface MyAnnotation {

    String value() default "hello";
}

可以看到,注解可以具有數組類型的元素,需要在大括號中指定數組元素的值,數組的元素由逗號分隔。

理解:這個其實也很好理解,可以類比我們的數組初始化,如下。

@ItemList(items = { "A", "B" })

// 數組初始化
String[] strs = {"A", "B"};
String[] strs1 = new String[]{"A", "B"};

4. 元注解:

對現有的注解進行解釋說明的注解。

JDK 5.0 提供的4種元注解:

  1. @Retention:指定所修飾的 Annotation 的生命周期:SOURCE\CLASS(默認行為)\RUNTIME。
    source:注解只保留在源文件,當Java文件編譯成class文件的時候,注解被遺棄;被編譯器忽略
    class:注解被保留到class文件,但jvm加載class文件時候被遺棄,這是默認的生命周期
    runtime:注解不僅被保存到class文件中,jvm加載class文件之后,仍然存在
    這3個生命周期分別對應於:Java源文件(.java文件) ---> .class文件 ---> 內存中的字節碼。

    只有聲明為RUNTIME生命周期的注解,才能通過反射獲取。
    那怎么來選擇合適的注解生命周期呢?
    首先要明確生命周期長度 SOURCE < CLASS < RUNTIME ,所以前者能作用的地方后者一定也能作用。一般如果需要在運行時去動態獲取注解信息,那只能用 RUNTIME 注解;如果要在編譯時進行一些預處理操作,比如生成一些輔助代碼(如 ButterKnife),就用 CLASS注解;如果只是做一些檢查性的操作,比如 @Override 和 @SuppressWarnings,則可選用 SOURCE 注解。

  2. @Target:用於指定被修飾的 Annotation 能用於修飾哪些程序元素
  3. @Documented:表示所修飾的注解在被javadoc解析時,保留下來。
  4. @Inherited:被它修飾的 Annotation 將具繼承性。

類比:元數據的概念:String name = "Tom";對現有數據的修飾

5. 如何獲取注解信息:

通過反射來進行獲取、調用。

前提:要求此注解的元注解Retention中聲明的生命周期狀態為:RUNTIME.

6. JDK 8.0中注解的新特性:

可重復注解、類型注解

6.1 可重復注解:

  1. 在MyAnnotation上聲明@Repeatable,成員值為MyAnnotations.class

  2. MyAnnotation的@Target@Retention等元注解與MyAnnotations相同。

6.2 類型注解:

ElementType.TYPE_PARAMETER 表示該注解能寫在類型變量的聲明語句中(如:泛型聲明。)

ElementType.TYPE_USE 表示該注解能寫在使用類型的任何語句中。


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM