在某些狀況下,一個類的對象是有限並且固定的。例如季節類,只能有 4 個對象。java
當類的對象是有限時,就應該使用枚舉,而不使用普通類。(枚舉對象是單例模式)程序員
例子spring
public class Test5 { public static void main(String[] args) { Season spring = Season.SPRING; spring.showInfo(); spring.test(); Season summer = Season.SUMMER; summer.showInfo(); summer.test(); Season spring2 = Season.SPRING; //每次執行Season.SPRING得到是相同的對象,枚舉類中的每一個枚舉對象都是單例模式 System.out.println(spring.equals(spring2));//true } } enum Season implements ITest{ //枚舉的實例對象都是默認修飾:private static final //下面的四個實例對象雖然沒有修飾,可是已是修飾了,只是沒顯式修飾。 SPRING("春天","春暖花開"),//此處至關於在調用有參的私有構造private season(String name,String desc) SUMMER("夏天","炎炎夏日"), AUTUMN("秋天","秋高氣爽"), WINTER("冬天","寒風凜冽"); private final String name; private final String desc; private Season(String name,String desc) { this.name = name; this.desc = desc; } public void showInfo() { System.out.println(this.name+ ": "+this.desc); } @Override public void test() { System.out.println("實現接口的方法,這是("+this.name+")的調用。"); } } interface ITest{ public void test(); }
比較重要的是compareTo()方法,這個以前TreeSet和TreeMap都有例子,這裏就不演示了。數組
註解做用:每當你建立描述符性質的類或者接口時,一旦其中包含重複性的工 做,就能夠考慮使用註解來簡化與自動化該過程。 Java提供了四種元註解,專門負責新註解的建立工做。 app
例子ide
import java.util.ArrayList; import java.util.List; public class Test6 { public static void main(String[] args) { TestB n = new TestB(); n.test1();//能夠看見方法名有刪除線,可是仍是可使用 //一般集合沒有指定泛型,會有警告 //可使用@SuppressWarnings()註解 : 抑制編譯器警告 @SuppressWarnings({ "rawtypes", "unused" }) List list = new ArrayList(); } } class TestA{ public void test() {} } class TestB extends TestA{ //常見 @Override註解,做用:重寫方法 @Override public void test() { // TODO Auto-generated method stub super.test(); } //過期的方法註解:@Deprecated,聲明該方法已通過時了 @Deprecated public void test1() { //過期的方法 System.out.println("過期的方法"); } }
例子工具
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; public class Test7 { //註解這些屬性有什麼用呢,一般都是要取出註解的屬性使用,要經過反射取註解的屬性,反射暫時沒學,略過 @TestAnn(id=1,desc = "test") int i; // @TestAnn(id=1,desc = "test")這裏會報錯,由於該註解已經限定只能在屬性使用。 public static void main(String[] args) { } } /** * * @author leak * 自定義註解格式 : @interface 註解名 * @Target: 註解聲明該自定義註解的「做用對象」,好比這個註解是做用於屬性/類/方法/接口/枚舉 * @Retention():聲明該註解的生命週期,就是該註解何時有效 * @Documented:Javadoc工具會將此註解標記元素的註解信息包含在javadoc中。默認,註解信息不會包含在Javadoc中。 */ @Target(ElementType.FIELD)//這裏是做用於屬性,也就是說這個自定義註解只能在屬性上使用 @Retention(RetentionPolicy.RUNTIME)//這裏是運行時都有效 @Documented @interface TestAnn{ public int id() default 0; public String desc() default ""; }
下面是註解的詳細信息,上面的只是簡單的介紹。學習
元註解的做用就是負責註解其餘註解。Java5.0定義了4個標準的metaannotation類型,它們被用來提供對其它 annotation類型做說明。 Java5.0定義的元註解: ui
1.@Target this
2.@Retention
3.@Documented
4.@Inherited
這些類型和它們所支持的類在java.lang.annotation包中能夠找到。
下面咱們看一下每一個元註解的做用和相應分參數的使用說明。
@Target說明了Annotation所修飾的對象範圍:Annotation可被用 於 packages、types(類、接口、枚舉、Annotation類型)、類型成員 (方法、構造方法、成員變量、枚舉值)、方法參數和本地變量(如循環變量、 catch參數)。在Annotation類型的聲明中使用了target可更加明晰其修飾 的目標。
做用:用於描述註解的使用範圍(即:被描述的註解能夠用在什麼地方)
取值(ElementType)有:
1.CONSTRUCTOR: 用於描述構造器
2.FIELD: 用於描述域
3.LOCAL_VARIABLE: 用於描述局部變量
4.METHOD: 用於描述方法
5.PACKAGE: 用於描述包
6.PARAMETER: 用於描述參數
7.TYPE: 用於描述類、接口(包括註解類型) 或enum聲明
使用示例:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /*** * * 實體註解接口 */ @Target(value = { ElementType.TYPE }) @Retention(value = RetentionPolicy.RUNTIME) public @interface Entity { /** * 實體默認firstLevelCache屬性爲false * * @return boolean */ boolean firstLevelCache() default false; /** * 實體默認secondLevelCache屬性爲false * @return boolean */ boolean secondLevelCache() default true; /** * 表名默認爲空 * @return String */ String tableName() default ""; /** * 默認以""分割註解 */ String split() default ""; }
@Retention定義了該Annotation被保留的時間長短:某些Annotation 僅出如今源代碼中,而被編譯器丟棄;而另外一些卻被編譯在class文件中;編譯 在class文件中的Annotation可能會被虛擬機忽略,而另外一些在class被裝載 時將被讀取(請注意並不影響class的執行,由於Annotation與class在使用
上是被分離的)。使用這個metaAnnotation能夠對 Annotation的「生命 週期」限制。
做用:表示須要在什麼級別保存該註釋信息,用於描述註解的生命週期 (即:被描述的註解在什麼範圍內有效)
取值(RetentionPoicy)有:
1.SOURCE:在源文件中有效(即源文件保留)
2.CLASS:在class文件中有效(即class保留)
3.RUNTIME:在運行時有效(即運行時保留)
使用示例:
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /*** * 字段註解接口 */ @Target(value = { ElementType.FIELD }) // 註解能夠被添加在屬性上 @Retention(value = RetentionPolicy.RUNTIME) // 註解保存在JVM運行時 刻,可以在運行時刻經過反射API來獲取到註解的信息 public @interface Column { String name(); // 註解的name屬性 Column註解的的RetentionPolicy的屬性值是RUTIME,這樣註解處理器能夠 // 經過反射,獲取到該註解的屬性值,從而去作一些運行時的邏輯處理 }
@Documented用於描述其它類型的annotation應該被做爲被標註的程序 成員的公共API,所以能夠被例如javadoc此類的工具文檔化。Documented是 一個標記註解,沒有成員。
@Inherited 元註解是一個標記註解,@Inherited闡述了某個被標註的 類型是被繼承的。
若是一個使用了@Inherited修飾的annotation類型被用於 一個class,則這個annotation將被用於該class的子類。
注意:
@Inherited annotation類型是被標註過的class的子類所繼承。
類並不從它所實現的接口繼承annotation,方法並不從它所重載的方法繼 承annotation。
當@Inherited annotation類型標註的annotation的Retention是 RetentionPolicy.RUNTIME,則反射API加強了這種繼承性。
若是咱們使用 java.lang.reflect去查詢一個@Inherited annotation類型的 annotation時,反射代碼檢查將展開工做:檢查class和其父類,直到發現指 定的annotation類型被發現,或者到達類繼承結構的頂層。
使用@interface自定義註解時,自動繼承了 java.lang.annotation.Annotation接口,由編譯程序自動完成其餘細 節。在定義註解時,不能繼承其餘的註解或接口。@interface用來聲明一個注 解,其中的每個方法其實是聲明瞭一個配置參數。方法的名稱就是參數的名 稱,返回值類型就是參數的類型(返回值類型只能是基本類型、Class、 String、enum)。能夠經過default來聲明參數的默認值。
定義註解格式:
public @interface 註解名 {定義體} 註解參數的可支持數據類型:
1.全部基本數據類型 (int,float,boolean,byte,double,char,long,short)
2.String類型
3.Class類型
4.enum類型
5.Annotation類型
6.以上全部類型的數組
Annotation類型裏面的參數該怎麼設定:
第一:只能用public或默認(default)這兩個訪問權修飾.例如,String value();這裏把方法設爲defaul默認類型;
第二:參數成員只能用基本類型 byte,short,char,int,long,float,double,boolean八種基本數據類型 和 String,Enum,Class,annotations等數據類型,以及這一些類型的數 組.例如,String value();這裏的參數成員就爲String;
第三:若是隻有一個參數成員,最好把參數名稱設爲"value",後加小括號. 例:下面的例子FruitName註解就只有一個參數成員。
簡單的自定義註解和使用註解實例:
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; //示例1 /*** *主鍵註解接口 */ @Target(value = { ElementType.FIELD }) @Retention(value = RetentionPolicy.RUNTIME) public @interface Id { } //示例2 /** 屬性不須要被持久化註解 **/ @Target(value = { ElementType.FIELD }) @Retention(value = RetentionPolicy.RUNTIME) @Documented @interface Transient { }
註解元素的默認值:
註解元素必須有肯定的值,要麼在定義註解的默認值中指定,要麼在使用注 解時指定,非基本類型的註解元素的值不可爲null。所以, 使用空字符串或0 做爲默認值是一種經常使用的作法。這個約束使得處理器很難表現一個元素的存在或 缺失的狀態,由於每一個註解的聲明中,全部元素都存在,而且都具備相應的值, 爲了繞開這個約束,咱們只能定義一些特殊的值,例如空字符串或者負數,一次 表示某個元素不存在,在定義註解時,這已經成爲一個習慣用法。
定義了註解,並在須要的時候給相關類,類屬性加上註解信息,若是沒有響應的 註解信息處理流程,註解能夠說是沒有實用價值。如何讓註解真真的發揮做用,
主要就在於註解處理方法,下一步咱們將學習註解信息的獲取和處理!
若是沒有用來讀取註解的方法和工做,那麼註解也就不會比註釋更有用處了。使 用註解的過程當中,很重要的一部分就是建立於使用註解處理器。Java SE5擴展 了反射機制的API,以幫助程序員快速的構造自定義註解處理器。
註解處理器類庫(java.lang.reflect.AnnotatedElement):
Java使用Annotation接口來表明程序元素前面的註解,該接口是全部 Annotation類型的父接口。除此以外,Java在java.lang.reflect 包下 新增了AnnotatedElement接口,該接口表明程序中能夠接受註解的程序元 素,該接口主要有以下幾個實現類:
Class:類定義
Constructor:構造器定義
Field:累的成員變量定義
Method:類的方法定義
Package:類的包定義
java.lang.reflect 包下主要包含一些實現反射功能的工具類,實際 上,java.lang.reflect 包全部提供的反射API擴充了讀取運行時 Annotation信息的能力。當一個Annotation類型被定義爲運行時的 Annotation後,該註解才能是運行時可見,當class文件被裝載時被保存在 class文件中的Annotation纔會被虛擬機讀取。
AnnotatedElement 接口是全部程序元素(Class、Method和 Constructor)的父接口,因此程序經過反射獲取了某個類的 AnnotatedElement對象以後,程序就能夠調用該對象的以下四個個方法來訪 問Annotation信息:
方法1:<T extends Annotation> T getAnnotation(Class<T> annotationClass): 返回改程序元素上存在的、指定類型的註解,若是該類 型註解不存在,則返回null。
方法2:Annotation[] getAnnotations():返回該程序元素上存在的 全部註解。
方法3:boolean is AnnotationPresent(Class<?extends Annotation> annotationClass):判斷該程序元素上是否包含指定類型的註解,存在則返回true,不然返回false.
方法4:Annotation[] getDeclaredAnnotations():返回直接存在 於此元素上的全部註釋。與此接口中的其餘方法不一樣,該方法將忽略繼承的注 釋。(若是沒有註釋直接存在於此元素上,則返回長度爲零的一個數組。)該方 法的調用者能夠隨意修改返回的數組;這不會對其餘調用者返回的數組產生任何 影響。
一個簡單的註解處理器:
import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; import java.lang.reflect.Field; import org.chen.day11.FruitColor.Color; /***********註解聲明***************/ /** 水果名稱註解 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented @interface FruitName { String value() default ""; } /** 水果顏色註解 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented @interface FruitColor { /** * 顏色枚舉 * * */ enum Color { BULE, RED, GREEN }; /** * 顏色屬性 * @return */ Color fruitColor() default Color.GREEN; } /** 水果供應者註解 */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) @Documented @interface FruitProvider { /** * 供應商編號 * @return */ public int id() default -1; /** * 供應商名稱 * @return */ public String name() default ""; /** * 供應商地址 * @return */ public String address() default ""; } /*********** 註解使用 ***************/ class Apple { // 下面進行註解賦值 @FruitName("Apple") private String appleName; @FruitColor(fruitColor = Color.RED) private String appleColor; @FruitProvider(id = 1, name = "陝西紅富士集團", address = "陝西省西安市延安路89號紅 富士大廈") private String appleProvider; // 下面的set/get方法對比註解,是否是註解更方便,若是賦值要屬性一個個用set方法設置 // get/set這裏只是對比,沒有使用到,可註釋掉 public void setAppleColor(String appleColor) { this.appleColor = appleColor; } public String getAppleColor() { return appleColor; } public void setAppleName(String appleName) { this.appleName = appleName; } public String getAppleName() { return appleName; } public void setAppleProvider(String appleProvider) { this.appleProvider = appleProvider; } public String getAppleProvider() { return appleProvider; } } /*********** 註解處理器 ***************/ public class FruitRun { public static void getFruitInfo(Class<?> clazz) { String strFruitName = " 水果名稱:"; String strFruitColor = " 水果顏色:"; String strFruitProvicer = "供應商信息:"; //getDeclaredFields():得到某個類的全部聲明的字段,即包括public、private和proteced,可是不包括父類的聲明字段。 Field[] fields = clazz.getDeclaredFields(); // 遍歷全部註解包含的信息 for (Field field : fields) { //註解算特殊的類 if (field.isAnnotationPresent(FruitName.class)) { FruitName fruitName = (FruitName) field.getAnnotation(FruitName.class); strFruitName = strFruitName + fruitName.value(); System.out.println(strFruitName);// 輸出水果名稱 } else if (field.isAnnotationPresent(FruitColor.class)) { FruitColor fruitColor = (FruitColor) field.getAnnotation(FruitColor.class); strFruitColor = strFruitColor + fruitColor.fruitColor().toString(); System.out.println(strFruitColor);// 輸出水果顏色 } else if (field.isAnnotationPresent(FruitProvider.class)) { FruitProvider fruitProvider = (FruitProvider) field.getAnnotation(FruitProvider.class); strFruitProvicer = " 供應商編號:" + fruitProvider.id() + " 供應 商名稱:" + fruitProvider.name() + " 供應商地址:" + fruitProvider.address(); System.out.println(strFruitProvicer);// 輸出水果詳細信息 } } } /*********** 輸出結果 ***************/ /** * @param args */ public static void main(String[] args) { //在Apple.class對屬性賦值的,getFruitInfo()取出註解裏面的值 FruitRun.getFruitInfo(Apple.class); } }