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

示例二:在編譯時(shí)進(jìn)行格式檢查(JDK內(nèi)置的三個(gè)基本注解) @Override: 限定重寫(xiě)父類(lèi)方法, 該注解只能用于方法 @Deprecated: 用于表示所修飾的元素(類(lèi), 方法等)已過(guò)時(shí)。通常是因?yàn)樗揎椀慕Y(jié)構(gòu)危險(xiǎn)或存在更好的選擇 @SuppressWarnings: 抑制編譯器警告
 示例三:跟蹤代碼依賴(lài)性,實(shí)現(xiàn)替代配置文件功能 Servlet3.0提供了注解(annotation),使得不再需要在web.xml文件中進(jìn)行Servlet的部署。
3. 自定義Annotation定義新的Annotation 類(lèi)型使用@interface 關(guān)鍵字 自定義注解自動(dòng)繼承了java.lang.annotation.Annotation接口 Annotation 的成員變量在 Annotation 定義中以無(wú)參數(shù)方法的形式來(lái)聲明。其方法名和返回值定義了該成員的名字和類(lèi)型。我們稱(chēng)為配置參數(shù)。類(lèi)型只能是八種基本數(shù)據(jù)類(lèi)型、String類(lèi)型、Class類(lèi)型、enum類(lèi)型、Annotation類(lèi)型、以上所有類(lèi)型的數(shù)組。 可以在定義 Annotation 的成員變量時(shí)為其指定初始值, 指定成員變量的初始值可使用default 關(guān)鍵字 如果只有一個(gè)參數(shù)成員,建議使用參數(shù)名為value 如果定義的注解含有配置參數(shù),那么使用時(shí)必須指定參數(shù)值,除非它有默認(rèn)值。格式是“參數(shù)名 = 參數(shù)值”,如果只有一個(gè)參數(shù)成員,且名稱(chēng)為value,可以省略“value=” 沒(méi)有成員定義的 Annotation 稱(chēng)為標(biāo)記; 包含成員變量的 Annotation 稱(chēng)為元數(shù)據(jù)Annotation 注意:自定義注解必須配上注解的信息處理流程(反射)才有意義。
//1. 注解聲明為 @interface
public @interface MyAnnotation {
//2. 內(nèi)部定義成員,通常使用 value表示
//3. 可用指定成員的默認(rèn)值,使用 default定義
//4. 如果自定義注解沒(méi)有成員,表明是一個(gè)表示作用
String vale() default "hello";
}
//5. 如果注解有成員,在使用注解時(shí),需要指明成員的值.
//@MyAnnotation(vale = "hello")
@MyAnnotation
class test {
public static void main(String[] args) {
}
}4. JDK中的元注解JDK 的元Annotation(對(duì)現(xiàn)有的注解進(jìn)行說(shuō)明的注解) 用于修飾其他Annotation 定義 JDK5.0提供了4個(gè)標(biāo)準(zhǔn)的meta-annotation類(lèi)型,分別是: Retention 指定所修飾的 Annotation的聲明周期 Target 用于指定被修飾的 Annotation能用于修飾那些程序元素 Documented 所修飾的注解被 javadoc解析時(shí),被保留下來(lái) Inherited 被它修飾的 Annotation將具有繼承性(通過(guò)反射獲取獲取注解信息)
元數(shù)據(jù)的理解: String name = “atguigu”;
@Retention: 只能用于修飾一個(gè) Annotation 定義, 用于指定該 Annotation 的生命周期, @Rentention 包含一個(gè) RetentionPolicy 類(lèi)型的成員變量, 使用@Rentention 時(shí)必須為該 value 成員變量指定值: RetentionPolicy.SOURCE:在源文件中有效(即源文件保留),編譯器直接丟棄這種策略的注釋 RetentionPolicy.CLASS:在class文件中有效(即class保留) , 當(dāng)運(yùn)行 Java 程序時(shí), JVM不會(huì)保留注解。 這是默認(rèn)值 RetentionPolicy.RUNTIME:在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留),當(dāng)運(yùn)行 Java 程序時(shí), JVM 會(huì)保留注釋。程序可以通過(guò)反射獲取該注釋。
 @Target: 用于修飾Annotation 定義, 用于指定被修飾的Annotation 能用于修飾哪些程序元素。 @Target 也包含一個(gè)名為 value 的成員變量。 | 取值(element type) | 描述 |
|---|
| constructor | 用于描述構(gòu)造器 | | field | 用于描述域 | | local_varibable | 用于描述局部變量 | | method | 用于描述方法 | | package | 用于描述包 | | parameter | 用于描述參數(shù) | | type | 用于描述類(lèi),接口(包括注解類(lèi)型)或者 enum聲明 |
@Documented: 用于指定被該元Annotation 修飾的Annotation 類(lèi)將被javadoc 工具提取成文檔。默認(rèn)情況下,javadoc是不包括注解的。 定義為Documented的注解必須設(shè)置Retention值為RUNTIME。 @Inherited: 被它修飾的 Annotation 將具有繼承性。如果某個(gè)類(lèi)使用了被@Inherited 修飾的 Annotation, 則其子類(lèi)將自動(dòng)具有該注解。 比如:如果把標(biāo)有 @Inherited注解的自定義的注解標(biāo)注在類(lèi)級(jí)別上,子類(lèi)則可以繼承父類(lèi)類(lèi)級(jí)別的注解 實(shí)際應(yīng)用中,使用較少
5. 利用反射獲取注解信息JDK 5.0 在 java.lang.reflect 包下新增了 AnnotatedElement 接口, 該接口代表程序中可以接受注解的程序元素 當(dāng)一個(gè)Annotation 類(lèi)型被定義為運(yùn)行時(shí)Annotation 后, 該注解才是運(yùn)行時(shí)可見(jiàn), 當(dāng) class 文件被載入時(shí)保存在 class 文件中的Annotation 才會(huì)被虛擬機(jī)讀取 程序可以調(diào)用AnnotatedElement對(duì)象的如下方法來(lái)訪問(wèn)Annotation 信息

6. JDK 8中注解的新特性Java 8對(duì)注解處理提供了兩點(diǎn)改進(jìn):可重復(fù)的注解及可用于類(lèi)型的注解。此外,反射也得到了加強(qiáng),在Java8中能夠得到方法參數(shù)的名稱(chēng)。這會(huì)簡(jiǎn)化標(biāo)注在方法參數(shù)上的注解。 可重復(fù)注解 //1. 注解聲明為 @interface
public @interface MyAnnotation {
//2. 內(nèi)部定義成員,通常使用 value表示
//3. 可用指定成員的默認(rèn)值,使用 default定義
//4. 如果自定義注解沒(méi)有成員,表明是一個(gè)表示作用
String vale() default "hello";
}
//5. 如果注解有成員,在使用注解時(shí),需要指明成員的值.
@interface MyAnnotations {
MyAnnotation[] value();
}
@MyAnnotations({@MyAnnotation(vale = "b"), @MyAnnotation(vale = "a")})
class Test {
}jdk8 //1. 注解聲明為 @interface
@Inherited
@Repeatable(MyAnnotations.class)
public @interface MyAnnotation {
//2. 內(nèi)部定義成員,通常使用 value表示
//3. 可用指定成員的默認(rèn)值,使用 default定義
//4. 如果自定義注解沒(méi)有成員,表明是一個(gè)表示作用
String vale() default "hello";
}
//5. 如果注解有成員,在使用注解時(shí),需要指明成員的值.
@interface MyAnnotations {
MyAnnotation[] value();
}
@MyAnnotation(vale = "123")
@MyAnnotation(vale = "abc")
class Test {
}在 MyAnnotation 上聲明 @Repeatable,成員值為 MyAnnotations.class MyAnnotation的 Target和 Retention和 MyAnnotations相同. jdk8 之前的寫(xiě)法
類(lèi)型注解 class TestTypeDefine<@TypeDefine() U> {
private U u;
public <@TypeDefine() T> void test(T t) {
}
}
@Target({ElementType.TYPE_PARAMETER})
@interface TypeDefine {
}JDK1.8之后,關(guān)于元注解 @Target的參數(shù)類(lèi)型 ElementType 枚舉值多了兩個(gè):TYPE_PARAMETER,TYPE_USE。 在Java 8之前,注解只能是在聲明的地方所使用,Java8開(kāi)始,注解可以應(yīng)用在任何地方。 ElementType.TYPE_PARAMETER 表示該注解能寫(xiě)在類(lèi)型變量的聲明語(yǔ)句中(如:泛型聲明)。 ElementType.TYPE_USE 表示該注解能寫(xiě)在使用類(lèi)型的任何語(yǔ)句中。
|