一、列舉
1、介紹
列舉類:類的物件只有有限個,確定的。當需要定義一組常量時,強烈建議使用列舉類。如果列舉類中只有一個物件,則可以作為單例模式的實現。
使用 enum 定義的列舉類預設繼承了 java.lang.Enum類,因此不能再繼承其他類。
2、列舉的實現
程式碼示例:方式一,JDK 5.0 之前,自定義列舉類
1 public class SeasonEnum { 2 3 // 列舉當前類的多個物件 4 public static final SeasonEnum SPRING = new SeasonEnum("01", "春天"); 5 public static final SeasonEnum SUMMER = new SeasonEnum("02", "夏天"); 6 public static final SeasonEnum AUTUMN = new SeasonEnum("03", "秋天"); 7 public static final SeasonEnum WINTER = new SeasonEnum("04", "冬天"); 8 9 private SeasonEnum(String code, String desc) { 10 this.code = code; 11 this.desc = desc; 12 } 13 14 private final String code; 15 private final String desc; 16 17 public String getCode() { 18 return code; 19 } 20 21 public String getDesc() { 22 return desc; 23 } 24 }
程式碼示例:方式二,JDK 5.0,可以使用 enum 關鍵字定義列舉
1 public enum SeasonEnum { 2 3 // 列舉當前類的多個物件 4 SPRING("01", "春天"), 5 SUMMER("02", "夏天"), 6 AUTUMN("03", "秋天"), 7 WINTER("04", "冬天"); 8 9 public static final Map<String, SeasonEnum> map = new HashMap<>(); 10 11 static { 12 for (SeasonEnum e : values()) { 13 map.put(e.code, e); 14 } 15 } 16 17 SeasonEnum(String code, String desc) { 18 this.code = code; 19 this.desc = desc; 20 } 21 22 private final String code; 23 private final String desc; 24 25 public String getCode() { 26 return code; 27 } 28 29 public String getDesc() { 30 return desc; 31 } 32 33 }
3、列舉實現介面
1 public enum SeasonEnum implements Info { 2 3 // 列舉當前類的多個物件 4 SPRING("01", "春天") { 5 @Override 6 public void show() { 7 System.out.println("春暖花開"); 8 } 9 }, 10 SUMMER("02", "夏天") { 11 @Override 12 public void show() { 13 System.out.println("夏日炎炎"); 14 } 15 }, 16 AUTUMN("03", "秋天"), 17 WINTER("04", "冬天"); 18 19 SeasonEnum(String code, String desc) { 20 this.code = code; 21 this.desc = desc; 22 } 23 24 private final String code; 25 private final String desc; 26 27 public String getCode() { 28 return code; 29 } 30 31 public String getDesc() { 32 return desc; 33 } 34 35 public void show() { 36 System.out.println("我的天氣"); 37 } 38 39 } 40 41 interface Info { 42 void show(); 43 }
4、API
values()方法:返回所有的列舉型別的物件。
valueOf(String str):檢查該字串是不是列舉類物件的"名字"。如不是,會有執行時異常:IllegalArgumentException。
toString():返回當前列舉類物件常量的名稱。
二、註解
1、介紹
從 JDK 5.0 開始,Java 增加了對後設資料(MetaData)的支援,也就是Annotation(註解)。
Annotation 其實就是程式碼裡的特殊標記,這些標記可以在編譯,類載入,執行時被讀取,並執行相應的處理。通過使用 Annotation,程式設計師可以在不改變原有邏輯的情況下,在原始檔中嵌入一些補充資訊。程式碼分析工具、開發工具和部署工具可以通過這些補充資訊進行驗證或者進行部署。
一定程度上,可以說:框架 = 註解 + 反射 + 設計模式。
2、示例
示例一、生成文件相關
@author:標明開發該類模組的作者,多個作者之間使用,分割。
@version:標明該類模組的版本。
@see:參考轉向,也就是相關主題。
@since:從哪個版本開始增加的。
@param:對方法中某引數的說明,如果沒有引數就不能寫。
@return:對方法返回值的說明,如果方法的返回值型別是void就不能寫。
@exception:對方法可能丟擲的異常進行說明,如果方法沒有用throws顯式丟擲的異常就不能寫。
示例二、在編譯時進行格式檢查(JDK內建的三個基本註解)
@Override:限定重寫父類方法,該註解只能用於方法。
@Deprecated:用於表示所修飾的元素(類,方法等)已過時。通常是因為所修飾的結構危險或存在更好的選擇。
@SuppressWarnings:抑制編譯器警告。
3、自定義註解
程式碼示例:
1 @Retention(RetentionPolicy.RUNTIME) 2 @Target({ElementType.TYPE, ElementType.FIELD}) 3 public @interface MyAnnotation { 4 String value() default "baidu"; 5 } 6 7 @MyAnnotation() 8 public class Person { 9 } 10 11 public class Main { 12 public static void main(String[] args) { 13 // 通過反射獲取Person類的註解 14 Class<Person> clazz = Person.class; 15 MyAnnotation annotation = clazz.getAnnotation(MyAnnotation.class); 16 17 // 獲取註解的值 18 String value = annotation.value(); 19 System.out.println(value); // baidu(輸出了預設值) 20 } 21 }
4、元註解
JDK 的元註解用於修飾其他註解定義。除了上面自定義註解用到的兩個,JDK5.0提供了4個標準的元註解,分別是:@Documented、@Inherited、@Retention、@Target。
@Retention:用於指定註解的生命週期,它包含一個RetentionPolicy列舉型別的成員變數。
原始碼示例:
1 @Documented 2 @Retention(RetentionPolicy.RUNTIME) 3 @Target(ElementType.ANNOTATION_TYPE) 4 public @interface Retention { 5 /** 6 * Returns the retention policy. 7 * @return the retention policy 8 */ 9 RetentionPolicy value(); 10 } 11 12 public enum RetentionPolicy { 13 /** 14 * Annotations are to be discarded by the compiler. 15 */ 16 SOURCE, 17 18 /** 19 * Annotations are to be recorded in the class file by the compiler 20 * but need not be retained by the VM at run time. This is the default 21 * behavior. 22 */ 23 CLASS, 24 25 /** 26 * Annotations are to be recorded in the class file by the compiler and 27 * retained by the VM at run time, so they may be read reflectively. 28 * 29 * @see java.lang.reflect.AnnotatedElement 30 */ 31 RUNTIME 32 }
原始碼中的英文註釋寫的很清楚,下面翻譯一下:
RetentionPolicy.SOURCE:在原始檔中有效(即原始檔保留),編譯器直接丟棄這種策略的註釋。
RetentionPolicy.CLASS:在class檔案中有效(即class保留),當執行 Java 程式時,JVM不會保留註解。這是預設值。
RetentionPolicy.RUNTIME:在執行時有效(即執行時保留),當執行 Java 程式時,JVM 會保留註釋。只有宣告為RUNTIME生命週期的註解,才可以通過反射獲取該註釋。
@Target:用於指定註解能用於修飾哪些程式元素,它包含一個ElementType列舉型別的成員變數。
原始碼示例:
1 @Documented 2 @Retention(RetentionPolicy.RUNTIME) 3 @Target(ElementType.ANNOTATION_TYPE) 4 public @interface Target { 5 ElementType[] value(); 6 } 7 8 public enum ElementType { 9 // 用於修飾類、介面,或者enum宣告 10 /** Class, interface (including annotation type), or enum declaration */ 11 TYPE, 12 13 // 用於修飾域 14 /** Field declaration (includes enum constants) */ 15 FIELD, 16 17 // 用於修飾方法 18 /** Method declaration */ 19 METHOD, 20 21 // 用於修飾引數 22 /** Formal parameter declaration */ 23 PARAMETER, 24 25 // 用於修飾構造器 26 /** Constructor declaration */ 27 CONSTRUCTOR, 28 29 // 用於修飾區域性變數 30 /** Local variable declaration */ 31 LOCAL_VARIABLE, 32 33 // 用於修飾註解 34 /** Annotation type declaration */ 35 ANNOTATION_TYPE, 36 37 // 用於修飾包 38 /** Package declaration */ 39 PACKAGE, 40 41 /** 42 * Type parameter declaration 43 * 44 * @since 1.8 45 */ 46 TYPE_PARAMETER, 47 48 /** 49 * Use of a type 50 * 51 * @since 1.8 52 */ 53 TYPE_USE 54 }
@Documented:用於指定被該註解修飾的類將被 javadoc 工具提取成文件。預設情況下,javadoc是不包括註解的。定義為Documented的註解必須設定Retention值為RUNTIME。
@Inherited:被它修飾的註解將具有繼承性。如果某個類使用了被@Inherited 修飾的註解,則其子類將自動具有該註解。
三、JDK8的新特性
1、介紹
Java 8對註解處理提供了兩點改進:可重複的註解及可用於型別的註解。此外,反射也得到了加強,在Java8中能夠得到方法引數的名稱。這會簡化標註在方法引數上的註解。
2、可重複註解
程式碼示例:方式一,JDK8之前
1 @Retention(RetentionPolicy.RUNTIME) 2 @Target({ElementType.TYPE}) 3 public @interface MyAnnotation { 4 String value() default "baidu"; 5 } 6 7 @Retention(RetentionPolicy.RUNTIME) 8 @Target({ElementType.TYPE}) 9 public @interface MyAnnotations { 10 MyAnnotation[] value(); 11 } 12 13 //@MyAnnotation("xiaoming") 14 //@MyAnnotation("xiaohong") 15 @MyAnnotations({@MyAnnotation("xiaoming"), @MyAnnotation("xiaohong")}) 16 public class Person { 17 private int age; 18 19 public void say() { 20 } 21 }
程式碼示例:方式二,JDK8之後
1 // 注:MyAnnotation的Target和Retention等元註解須與MyAnnotations相同 2 @Repeatable(MyAnnotations.class) 3 @Retention(RetentionPolicy.RUNTIME) 4 @Target({ElementType.TYPE}) 5 public @interface MyAnnotation { 6 String value() default "baidu"; 7 } 8 9 @Retention(RetentionPolicy.RUNTIME) 10 @Target({ElementType.TYPE}) 11 public @interface MyAnnotations { 12 MyAnnotation[] value(); 13 } 14 15 @MyAnnotation("xiaoming") 16 @MyAnnotation("xiaohong") 17 public class Person { 18 private int age; 19 20 public void say() { 21 } 22 }
3、型別註解
在Java 8之前,註解只能在宣告的地方使用。Java8開始,註解可以應用在任何地方。
ElementType.TYPE_PARAMETER:表示該註解能寫在型別變數的宣告語句中(如:泛型宣告)。
ElementType.TYPE_USE:表示該註解能寫在使用型別的任何語句中。
程式碼示例:TYPE_PARAMETER
1 @Retention(RetentionPolicy.RUNTIME) 2 @Target({ElementType.TYPE, ElementType.TYPE_PARAMETER}) 3 public @interface MyAnnotation { 4 String value() default "baidu"; 5 } 6 7 @MyAnnotation 8 public class Person<@MyAnnotation T> { 9 private T age; 10 11 public void say() throws RuntimeException { 12 List<String> list = new ArrayList<>(); 13 14 int num = (int) 10L; 15 } 16 }
程式碼示例:TYPE_USE
1 @Retention(RetentionPolicy.RUNTIME) 2 @Target({ElementType.TYPE, ElementType.TYPE_PARAMETER, ElementType.TYPE_USE}) 3 public @interface MyAnnotation { 4 String value() default "baidu"; 5 } 6 7 @MyAnnotation 8 public class Person<@MyAnnotation T> { 9 private T age; 10 11 public void say() throws @MyAnnotation RuntimeException { 12 List<@MyAnnotation String> list = new ArrayList<>(); 13 14 int num = (@MyAnnotation int) 10L; 15 } 16 }