13 Java枚舉和註解

Java枚舉

在某些狀況下,一個類的對象是有限並且固定的。例如季節類,只能有 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();
}
View Code

枚舉類的經常使用方法

 比較重要的是compareTo()方法,這個以前TreeSet和TreeMap都有例子,這裏就不演示了。數組

Annotation註解

註解概述

註解做用:每當你建立描述符性質的類或者接口時,一旦其中包含重複性的工 做,就能夠考慮使用註解來簡化與自動化該過程。 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("過期的方法");
    }
}
View Code

自定義註解

 

 例子工具

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 "";
}
View Code

下面是註解的詳細信息,上面的只是簡單的介紹。學習

元註解     

元註解的做用就是負責註解其餘註解。Java5.0定義了4個標準的metaannotation類型,它們被用來提供對其它 annotation類型做說明。 Java5.0定義的元註解:      ui

1.@Target      this

2.@Retention       

3.@Documented   

4.@Inherited  

這些類型和它們所支持的類在java.lang.annotation包中能夠找到。

下面咱們看一下每一個元註解的做用和相應分參數的使用說明。

@Target    

@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 "";
}
View Code

@Retention  

@Retention定義了該Annotation被保留的時間長短:某些Annotation 僅出如今源代碼中,而被編譯器丟棄;而另外一些卻被編譯在class文件中;編譯 在class文件中的Annotation可能會被虛擬機忽略,而另外一些在class被裝載 時將被讀取(請注意並不影響class的執行,由於Annotation與class在使用
上是被分離的)。使用這個meta­Annotation能夠對 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,這樣註解處理器能夠
    // 經過反射,獲取到該註解的屬性值,從而去作一些運行時的邏輯處理
}
View Code

@Documented  

@Documented用於描述其它類型的annotation應該被做爲被標註的程序 成員的公共API,所以能夠被例如javadoc此類的工具文檔化。Documented是 一個標記註解,沒有成員。

@Inherited    

@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 {
}
View Code

註解元素的默認值:    

註解元素必須有肯定的值,要麼在定義註解的默認值中指定,要麼在使用注 解時指定,非基本類型的註解元素的值不可爲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);
    }
}
View Code
相關文章
相關標籤/搜索