列舉的使用
1. 列舉簡介
- 類的物件只有有限個,確定的,舉例如下:
星期:Monday(星期一)、......、Sunday(星期天)
性別:Man(男)、Woman(女)
季節:Spring(春節)......Winter(冬天)
支付方式:Cash(現金)、WeChatPay(微信)、Alipay(支付寶)、BankCard(銀行卡)、CreditCard(信用卡)
就職狀態:Busy、Free、Vocation、Dimission
訂單狀態:Nonpayment(未付款)、Paid(已付款)、Delivered(已發貨)、 Return(退貨)、Checked(已確認)Fulfilled(已配貨)、
執行緒狀態:創建、就緒、運行、阻塞、死亡 - 當需要定義一組常量時,強烈建議使用列舉類
- 列舉類的實作
JDK1.5之前需要自定義列舉類
JDK 1.5 新增的 enum 關鍵字用于定義列舉類
若列舉只有一個物件, 則可以作為一種單例模式的實作方式, - 列舉類的屬性
列舉類物件的屬性不應允許被改動, 所以應該使用 private final 修飾
列舉類的使用 private final 修飾的屬性應該在構造器中為其賦值
若列舉類顯式的定義了帶引數的構造器, 則在列出列舉值時也必須對應的傳入引數
2. 如何自定義列舉類(jdk 5.0之前)
- 私有化類的構造器,保證不能在類的外部創建其物件
- 在類的內部創建列舉類的實體,宣告為:public static final
- 物件如果有實體變數,應該宣告為 private final,并在構造器中初始化
- 其他訴求:獲取列舉物件的屬性
//自定義列舉類
class Season {
//1. 宣告 Season 屬性
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 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. 其他訴求:獲取列舉物件的屬性
public String getSeasonName() {
return seasonName;
}
public String getSeasonDesc() {
return seasonDesc;
}
@Override
public String toString() {
return "Season{" +
"seasonName='" + seasonName + '\'' +
", seasonDesc='" + seasonDesc + '\'' +
'}';
}
}
public class SeasonTest {
public static void main(String[] args) {
System.out.println(Season.AUTUMN);//Season{seasonName='秋天', seasonDesc='秋高氣爽'}
}
}
- 使用說明
使用 enum 定義的列舉類默認繼承了java.lang.Enum類,因此不能再繼承其他類
列舉類的構造器只能使用 private 權限修飾符
列舉類的所有實體必須在列舉類中顯式列出(, 分隔 ; 結尾),列出的實體系統會自動添加 public static final 修飾
必須在列舉類的第一行宣告列舉類物件 - JDK 1.5 中可以在 switch 運算式中使用 Enum 定義的列舉類的物件作為運算式, case 子句可以直接使用列舉值的名字, 無需添加列舉類作為限定,
3. 如何使用關鍵字(jdk 5.0) enum定義列舉類
- 提供當前列舉類的多個物件 : 多個物件之間用 逗號 隔開,末尾物件 分號 結束
- 宣告 自定義列舉類的 屬性
- 私有化類的構造器,并給物件屬性賦值
- 其他訴求:獲取列舉物件的屬性
//自定義列舉類
enum Season1 {
//1. 提供當前列舉類的多個物件 : 多個物件之間用 逗號 隔開,末尾物件 分號 結束
SPRING("春天", "春暖花開"),
SUMMER("夏天", "夏日炎炎"),
AUTUMN("秋天", "秋高氣爽"),
WINTER("冬天", "冰天雪地");
//2. 宣告 Season1 屬性
private final String seasonName;
private final String seasonDesc;
//3. 私有化類的構造器,并給物件屬性賦值
private Season1(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//4. 其他訴求:獲取列舉物件的屬性
public String getSeasonDesc() {
return seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
}
public class SeasonTest1 {
public static void main(String[] args) {
System.out.println(Season1.WINTER);//WINTER
System.out.println(Season1.class.getSuperclass());//class java.lang.Enum
}
}
4. Enum(jdk 1.5 )類的主要方法
java.lang public abstract class Enum<E extends Enum<E>> extends Object implements Comparable<E>, Serializable
protected Enum?(String name,int ordinal)唯一的建構式, 程式員無法呼叫此建構式,
它由編譯器回應列舉型別宣告發出的代碼使用,
protected Object clone?() 列舉型別不能被 Clone.為了防止子類實作克隆方法,
Enum實作了一個拋出CloneNotSupportedException例外的不變 Clone(),
int compareTo?(E o) 列舉型別實作了 Comparable 介面,這樣可用比較兩個列舉常量的大小(按照宣告的順序排序),
boolean equals?(Object other) 在列舉型別中可用直接使用 "=="來比較兩個列舉常量是否相等,
Enum提供這個 equals()方法,也是直接使用 "=="實作的.它的存在是為了在 set,list和map中使用.注意equals()是不可變的.
protected void finalize?() 列舉類不能有finalize方法,
Class<E> getDeclaringClass?() 得到列舉常量所屬列舉型別的 Class物件.可用用它來判斷兩個列舉常量是否屬于同一個列舉型別,
int hashCode?() Enum實作了 hashCode()來和 equals()保持一致.它也是不可變的,
String name?() 回傳此列舉常量的名稱,與其列舉宣告中宣告的完全相同,
int ordinal?() 回傳此列舉常數的序數(其列舉宣告中的位置,其中初始常數的序數為零),
String toString?() 得到當前列舉常量的名稱,你可以通過從寫這個方法來使得到的結果更易讀.
static <T extends Enum<T>> T valueOf?(Class<T> enumType, String name) 傳遞列舉型別的 Class物件和列舉常量名稱
給靜態方法 valueOf,會得到與引數匹配的列舉常量,
values(); 回傳列舉型別的物件陣列.該方法可用很方便的遍歷所有的列舉值.
valueOf(String str); 可用把一個字串轉為對應的列舉類物件.要求字串必須是列舉物件的 "名字".如果不是,會有運行時例外
IllegalArgumentException.
toString(); 回傳當前列舉物件常量的名稱
- Methods inherited from class java.lang.Object : getClass, notify, notifyAll, wait, wait, wait
5. 實作介面的列舉類
- 和普通 Java 類一樣,列舉類可以實作一個或多個介面
- 若每個列舉值在呼叫實作的介面方法呈現相同的行為方式,則只要統一實作該方法即可,
- 若需要每個列舉值在呼叫實作的介面方法呈現出不同的行為方式,則可以讓每個列舉值分別來實作該方法
//情況1: 實作介面,在 enum類中實作抽象方法
//情況2: 讓列舉的物件分別實作介面中的抽象方法
interface Info {
void show();
}
//自定義列舉類
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("大約在冬季");
}
};
//2. 宣告 Season1 屬性
private final String seasonName;
private final String seasonDesc;
//3. 私有化類的構造器,并給物件屬性賦值
private Season1(String seasonName, String seasonDesc) {
this.seasonName = seasonName;
this.seasonDesc = seasonDesc;
}
//5. 其他訴求:獲取列舉物件的屬性
public String getSeasonDesc() {
return seasonDesc;
}
public String getSeasonName() {
return seasonName;
}
/*@Override
public void show() {
System.out.println("這是一個季節");
}*/
}
//呼叫 :Season1.AUTUMN.show();
注解的使用
1. 注解(Annotation)概述
- 從 JDK 5.0 開始, Java 增加了對元資料(MetaData) 的支持, 也就是Annotation(注解)
- Annotation 其實就是代碼里的特殊標記, 這些標記可以在編譯, 類加載, 運行時被讀取, 并執行相應的處理,通過使用 Annotation, 程式員可以在不改變原有邏輯的情況下, 在源檔案中嵌入一些補充資訊,代碼分析工具、開發工具和部署工具可以通過這些補充資訊進行驗證或者進行部署,
- Annotation 可以像修飾符一樣被使用, 可用于修飾包,類, 構造器, 方法, 成員變數, 引數, 區域變數的宣告, 這些資訊被保存在 Annotation的 “name=value” 對中,
- 在JavaSE中,注解的使用目的比較簡單,例如標記過時的功能,忽略警告等,在JavaEE/Android中注解占據了更重要的角色,例如用來配置應用程式的任何切面,代替 JavaEE舊版中所遺留的繁冗代碼和 XML配置等,
- 未來的開發模式都是基于注解的,JPA是基于注解的,Spring2.5以上都是基于注解的,Hibernate3.x以后也是基于注解的,現在的Struts2有一部分也是基于注解的了,注解是一種趨勢,一定程度上可以說:框架 = 注解 + 反射 + 設計模式,
2. 常見的Annotation示例
-
使用 Annotation 時要在其前面增加 @ 符號, 并把該Annotation 當成一個修飾符使用,用于修飾它支持的程式元素
-
示例一:生成檔案相關的注解
- @author 標明開發該類模塊的作者,多個作者之間使用,分割
- @version 標明該類模塊的版本
- @see 參考轉向,也就是相關主題
- @since 從哪個版本開始增加的
- @param 對方法中某引數的說明,如果沒有引數就不能寫
- @return 對方法回傳值的說明,如果方法的回傳值型別是void就不能寫
- @exception 對方法可能拋出的例外進行說明,如果方法沒有用throws顯式拋出的例外就不能寫其中
@param @return 和@exception 這三個標記都是只用于方法的, @param的格式要求:@param 形參名形參型別 形參說明
@return 的格式要求:@return 回傳值型別回傳值說明
@exception的格式要求:@exception 例外型別例外說明
@param和@exception可以并列多個

-
示例二:在編譯時進行格式檢查(JDK內置的三個基本注解)
@Override: 限定重寫父類方法, 該注解只能用于方法
@Deprecated: 用于表示所修飾的元素(類, 方法等)已過時,通常是因為所修飾的結構危隙訓存在更好的選擇
@SuppressWarnings: 抑制編譯器警告

-
示例三:跟蹤代碼依賴性,實作替代組態檔功能
Servlet3.0提供了注解(annotation),使得不再需要在web.xml檔案中進行Servlet的部署,
3. 自定義Annotation
- 定義新的Annotation 型別使用@interface 關鍵字
- 自定義注解自動繼承了
java.lang.annotation.Annotation介面 - Annotation 的成員變數在 Annotation 定義中以無引數方法的形式來宣告,其方法名和回傳值定義了該成員的名字和型別,我們稱為配置引數,型別只能是八種基本資料型別、String型別、Class型別、enum型別、Annotation型別、以上所有型別的陣列,
- 可以在定義 Annotation 的成員變數時為其指定初始值, 指定成員變數的初始值可使用default 關鍵字
- 如果只有一個引數成員,建議使用引數名為value
- 如果定義的注解含有配置引數,那么使用時必須指定引數值,除非它有默認值,格式是“參數名 = 引數值”,如果只有一個引數成員,且名稱為value,可以省略“value=https://www.cnblogs.com/zk2020/p/”
- 沒有成員定義的 Annotation 稱為標記; 包含成員變數的 Annotation 稱為元資料Annotation
- 注意:自定義注解必須配上注解的資訊處理流程(反射)才有意義,
//1. 注解宣告為 @interface
public @interface MyAnnotation {
//2. 內部定義成員,通常使用 value表示
//3. 可用指定成員的默認值,使用 default定義
//4. 如果自定義注解沒有成員,表明是一個表示作用
String vale() default "hello";
}
//5. 如果注解有成員,在使用注解時,需要指明成員的值.
//@MyAnnotation(vale = "hello")
@MyAnnotation
class test {
public static void main(String[] args) {
}
}
4. JDK中的元注解
- JDK 的元Annotation(對現有的注解進行說明的注解) 用于修飾其他Annotation 定義
- JDK5.0提供了4個標準的meta-annotation型別,分別是:
Retention 指定所修飾的 Annotation的宣告周期
Target 用于指定被修飾的 Annotation能用于修飾那些程式元素
Documented 所修飾的注解被 javadoc決議時,被保留下來
Inherited 被它修飾的 Annotation將具有繼承性(通過反射獲取獲取注解資訊)
元資料的理解:
String name = “atguigu”;
-
@Retention: 只能用于修飾一個 Annotation 定義, 用于指定該 Annotation 的生命周期, @Rentention 包含一個 RetentionPolicy 型別的成員變數, 使用@Rentention 時必須為該 value 成員變數指定值:
RetentionPolicy.SOURCE:在源檔案中有效(即源檔案保留),編譯器直接丟棄這種策略的注釋
RetentionPolicy.CLASS:在class檔案中有效(即class保留) , 當運行 Java 程式時, JVM不會保留注解, 這是默認值
RetentionPolicy.RUNTIME:在運行時有效(即運行時保留),當運行 Java 程式時, JVM 會保留注釋,程式可以通過反射獲取該注釋,

-
@Target: 用于修飾Annotation 定義, 用于指定被修飾的Annotation 能用于修飾哪些程式元素, @Target 也包含一個名為 value 的成員變數,
取值(element type) 描述 constructor 用于描述構造器 field 用于描述域 local_varibable 用于描述區域變數 method 用于描述方法 package 用于描述包 parameter 用于描述引數 type 用于描述類,介面(包括注解型別)或者 enum宣告 -
@Documented: 用于指定被該元Annotation 修飾的Annotation 類將被javadoc 工具提取成檔案,默認情況下,javadoc是不包括注解的,
定義為Documented的注解必須設定Retention值為RUNTIME, -
@Inherited: 被它修飾的 Annotation 將具有繼承性,如果某個類使用了被@Inherited 修飾的 Annotation, 則其子類將自動具有該注解,
比如:如果把標有 @Inherited注解的自定義的注解標注在類級別上,子類則可以繼承父類類級別的注解
實際應用中,使用較少
5. 利用反射獲取注解資訊
- JDK 5.0 在 java.lang.reflect 包下新增了 AnnotatedElement 介面, 該介面代表程式中可以接受注解的程式元素
- 當一個Annotation 型別被定義為運行時Annotation 后, 該注解才是運行時可見, 當 class 檔案被載入時保存在 class 檔案中的Annotation 才會被虛擬機讀取
- 程式可以呼叫AnnotatedElement物件的如下方法來訪問Annotation 資訊

6. JDK 8中注解的新特性
- Java 8對注解處理提供了兩點改進:可重復的注解及可用于型別的注解,此外,反射也得到了加強,在Java8中能夠得到方法引數的名稱,這會簡化標注在方法引數上的注解,
- 可重復注解
- 在 MyAnnotation 上宣告 @Repeatable,成員值為 MyAnnotations.class
- MyAnnotation的 Target和 Retention和 MyAnnotations相同.
jdk8 之前的寫法
jdk8//1. 注解宣告為 @interface public @interface MyAnnotation { //2. 內部定義成員,通常使用 value表示 //3. 可用指定成員的默認值,使用 default定義 //4. 如果自定義注解沒有成員,表明是一個表示作用 String vale() default "hello"; } //5. 如果注解有成員,在使用注解時,需要指明成員的值. @interface MyAnnotations { MyAnnotation[] value(); } @MyAnnotations({@MyAnnotation(vale = "b"), @MyAnnotation(vale = "a")}) class Test { }//1. 注解宣告為 @interface @Inherited @Repeatable(MyAnnotations.class) public @interface MyAnnotation { //2. 內部定義成員,通常使用 value表示 //3. 可用指定成員的默認值,使用 default定義 //4. 如果自定義注解沒有成員,表明是一個表示作用 String vale() default "hello"; } //5. 如果注解有成員,在使用注解時,需要指明成員的值. @interface MyAnnotations { MyAnnotation[] value(); } @MyAnnotation(vale = "123") @MyAnnotation(vale = "abc") class Test { } - 型別注解
- JDK1.8之后,關于元注解 @Target的引數型別 ElementType 列舉值多了兩個:TYPE_PARAMETER,TYPE_USE,
- 在Java 8之前,注解只能是在宣告的地方所使用,Java8開始,注解可以應用在任何地方,
ElementType.TYPE_PARAMETER 表示該注解能寫在型別變數的宣告陳述句中(如:泛型宣告),
ElementType.TYPE_USE 表示該注解能寫在使用型別的任何陳述句中,
class TestTypeDefine<@TypeDefine() U> { private U u; public <@TypeDefine() T> void test(T t) { } } @Target({ElementType.TYPE_PARAMETER}) @interface TypeDefine { }
轉載請註明出處,本文鏈接:https://www.uj5u.com/houduan/302346.html
標籤:Java
