一、枚舉類的使用
1. 枚舉類的說明:
枚舉類的理解:類的對象只有有限個,確定的。我們稱此類為枚舉類
當需要定義一組常量時,強烈建議使用枚舉類
- 枚舉類的實現:
- JDK 5.0以前需要自定義
- JDK 5.0后新增enum關鍵字用於定義枚舉類
如果枚舉類中只一個對象,則可以作為單例模式的實現方式。
枚舉類的屬性:
枚舉類對象的屬性不應允許被改動,所以應該使用 private final 修飾 枚舉類的使用 private final修飾的屬性應該在構造器中為其賦值 若枚舉類顯式的定義了帶參數的構造器,則在列出枚舉值時也必須對應的傳入參數
2. 如何自定義枚舉類?
步驟:
- 私有化構造器,保證不能在類的外部創建其對象;
在類的內部創建枚舉類的實例。聲明為:
public static final
;- 因為要通過類來調取使用,靜態在類里面了,不動了,所以需要 public static
- 又不允許改變,所以為 final。
這個枚舉類里面有好幾個對象,每個對象相當於是一個常量
如果這個類只有一個對象,那么可以看成是一個單例模式對象如果有實例變量,應該聲明為
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類的常用方法:
values()
方法:返回枚舉類型的對象數組。該方法可以很方便地遍歷所有的枚舉值。valueOf(String str)
:可以把一個字符串轉為對應的枚舉類對象。要求字符串必須是枚舉類對象的“名字”.如不是,會有運行時異常IllegalArgumentExceptiontoString()
:返回當前枚舉類對象常量的名稱(可重寫自定義)name()
:返回當前枚舉類對象常量的名稱(final不可重寫)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類定義的枚舉類對象分別實現接口:
使用說明:
- 和普通Java類一樣,枚舉類可以實現一個或多個接口
- 若每個枚舉值在調用實現的接口方法呈現相同的行為方式,則只要統一實現該方法即可。
- 若需要每個枚舉值在調用實現的接口方法呈現出不同的行為方式,則可以讓每個枚舉值分別來實現該方法
代碼示例:
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. 注解的理解
jdk 5.0 新增的功能
Annotation 其實就是代碼里的特殊標記, 這些標記可以在編譯, 類加載, 運行時被讀取, 並執行相應的處理。通過使用 Annotation,程序員可以在不改變原邏輯的情況下, 在源文件中嵌入一些補充信息。
Annotation可以像修飾符一樣使用,可以用來修飾包、類、構造器、方法、成員變量、參數、局部變量的聲明,這些信息被保存在Annotation的“name = value”對中。
在JavaSE中,注解的使用目的比較簡單,例如標記過時的功能,忽略警告等。在JavaEE/Android 中注解占據了更重要的角色,例如用來配置應用程序的任何切面,代替JavaEE舊版中所遺留的繁冗 代碼和XML配置等。
框架 = 注解 + 反射機制 + 設計模式
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定義
- 注解聲明為:
@interface
內部定義成員,通常使用無參無異常方法
value()
表示如果成員只有一個,那么這個成員必須取名為value(),使用時可以忽略成員名和賦值號(=)。
理解:為什么要使用無參無異常方法呢,我認為那是因為,如果使用變量來進行存儲的話,在接口中,屬性變量會變為常量,占取空間;
而我們這個注解又不是那么的需要這個屬性(占空間),只是在屬性調用到的時候起作用。
需要在調用的時候才起作用,那肯定是方法比較符合條件了。記憶:這個注解的使用方式比較類似於方法,如@
Params(...)
,所以里面的注解實現也都用方法value()
表示。- 可以指定成員的默認值,使用
default
定義 如果自定義注解沒成員,表明是一個標識作用。
說明:
- 如果注解有成員,在使用注解時,需要指明成員的值。
- 自定義注解必須配上注解的信息處理流程(使用反射)才意義。
- 自定義注解通過都會指明兩個元注解:
@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種元注解:
@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 注解。@Target
:用於指定被修飾的 Annotation 能用於修飾哪些程序元素
@Documented
:表示所修飾的注解在被javadoc解析時,保留下來。@Inherited
:被它修飾的 Annotation 將具繼承性。
類比:元數據的概念:String name = "Tom";對現有數據的修飾
5. 如何獲取注解信息:
通過反射來進行獲取、調用。
前提:要求此注解的元注解Retention中聲明的生命周期狀態為:RUNTIME.
6. JDK 8.0中注解的新特性:
可重復注解、類型注解
6.1 可重復注解:
在MyAnnotation上聲明
@Repeatable
,成員值為MyAnnotations.classMyAnnotation的
@Target
和@Retention
等元注解與MyAnnotations相同。
6.2 類型注解:
ElementType.TYPE_PARAMETER
表示該注解能寫在類型變量的聲明語句中(如:泛型聲明。)
ElementType.TYPE_USE
表示該注解能寫在使用類型的任何語句中。