java 新特性 ----Annontation (8)


一、概念
j2se 提供了很多新特性。其中一個很重要的特性就是對元數據(Metadata)的支持。在j2se 5.0 中,這種數據被稱爲註釋(Annontation).通過使用註釋,程序開發人員可以在不改變原有邏輯的情況下,在源文件嵌入一些補充的信息。
Annontation 可以用來修飾類、屬性、方法,而且Annontation 不影響程序運行,無論是否使用Annontation 代碼都可以正常運行。
Java.lang.annontation.Annontation 是Annontation 的接口,只要是Annontation 都必須實現此接口。此接口定義如下:

public interface Annontation{
    public Class<? extends Annontation> annotationType();
    public boolean equals(Object obj) ;
    public int hashCode();
    String toString();
}

二、原理
  Annotation其實是一種接口。通過Java的反射機制相關的API來訪問annotation信息。相關類(框架或工具中的類)根據這些信息來決定如何使用該程序元素或改變它們的行爲。
  annotation是不會影響程序代碼的執行,無論annotation怎麼變化,代碼都始終如一地執行。
  Java語言解釋器在工作時會忽略這些annotation,因此在JVM中這些annotation是“不起作用”的,只能通過配套的工具才能對這些annontaion類型的信息進行訪問和處理。
  Annotation與interface的異同:
    1)、Annotation類型使用關鍵字@interface而不是interface。
  這個關鍵字聲明隱含了一個信息:它是繼承了java.lang.annotation.Annotation接口,並非聲明瞭一個interface
    2)、Annotation類型、方法定義是獨特的、受限制的。
  Annotation類型的方法必須聲明爲無參數、無異常拋出的。這些方法定義了annotation的成員:方法名成爲了成員名,而方法返回值成爲了成員的類型。而方法返回值類型必須爲primitive類型、Class類型、枚舉類型、annotation類型或者由前面類型之一作爲元素的一維數組。方法的後面可以使用default和一個默認數值來聲明成員的默認值,null不能作爲成員默認值,這與我們在非annotation類型中定義方法有很大不同。
  Annotation類型和它的方法不能使用annotation類型的參數、成員不能是generic。只有返回值類型是Class的方法可以在annotation類型中使用generic,因爲此方法能夠用類轉換將各種類型轉換爲Class。
    3)、Annotation類型又與接口有着近似之處。
  它們可以定義常量、靜態成員類型(比如枚舉類型定義)。Annotation類型也可以如接口一般被實現或者繼承。

三、應用場合
annotation一般作爲一種輔助途徑,應用在軟件框架或工具中,在這些工具類中根據不同的annontation註解信息採取不同的處理過程或改變相應程序元素(類、方法及成員變量等)的行爲。
例如:Junit、Struts、Spring等流行工具框架中均廣泛使用了annontion。使代碼的靈活性大提高。

四、常見使用方法
1、系統內間的Annontation 類型:
    @Override:覆寫的Annontation;
    @Deprecated:不贊成使用的 Annontation ;
    @SuppressWarnings:壓制安全警告的Annontation.
1.1、@Override 主要是在方法覆寫時使用,用於保證覆寫的正確性。
@Override 註釋的作用:
代碼:
package com.zsc.annon;

public class OverrideAnnontationTest {
    public static void main(String[] args) {

        Person per = new Student();
        System.out.println(per.getInfo());
    }
}
class Person{
    public String getInfo(){
        return "這是一個Person類";
    }
}
class Student extends Person{
    @Override
    public String getInfo(){
        return "這是一個Student類";
    }
}

錯誤的覆寫:
package com.zsc.annon;

public class OverrideAnnontationTest {
    public static void main(String[] args) {

        Person per = new Student();
        System.out.println(per.getInfo());
    }
}
class Person{
    public String getInfo(){
        return "這是一個Person類";
    }
}
class Student extends Person{
    @Override
    public String getiInfo(){    // 提示錯誤
        return "這是一個Student類";
    }
}

注意:@Override 使用限制。
@Override 在使用時只能在方法上使用,而其他元素,如類、屬性等上面是不可以使用的。

2、@Deprecated
@Deprecated 註釋的主要功能是用來聲明一個不建議使用的方法。如果在程序中使用了此方法,則在編譯時將出現警告信息。

使用 @Deprecated 生命一個不建議使用的方法:
代碼:
package com.zsc.annon;

public class DeprecatedAnnontationTest {
    public static void main(String[] args) {
        Person per = new Person();
        System.out.println(per.getInfo());
    }
}
class Persons{
    @Deprecated
    public String getInfo(){
        return "這是一個Persons類";
    }
}

3、@SuppressWarnings
@SuppressWarnings 註釋的主要功能是用來壓制警告,例如,如果在一個聲明時沒有指明泛型,則肯定會編譯時產生,那麼此時就可以使用@SuppressWarnings 壓制這種警告。
壓制一個警告:
代碼:
package com.zsc.annon;

public class SuppressWarningsAnnontationTest {
    @SuppressWarnings("unchecked")
    public static void main(String[] args) {
        Personss per = new Personss();
        per.setVar("張三");
        System.out.println("內容:"+per.getVar());
    }
}
class Personss<T>{
    private T var ;
    public T getVar(){
        return var ;
    }
    public void setVar(T var){
        this.var = var ;
    }
}

4、自定義Annontation
4.1、定以簡單的Annontation
格式 [public] @interface Annontation名稱{
    數據類型 變量名稱();
}
要定以 Annontation 必須使用 @interface 的方式進行定義,在定義Annontation 時也可以定以各種變量,但是變量定義之後必須用“()”。
自定義一個 Annontation
代碼:
package com.zsc.annon;
public @interface AnnontationTest {

}

4.2 向Annontation 中設置內容:
定義MyAnnontation ,可以接受一個變量
代碼:
package com.zsc.annon;
public @interface MyAnnontation {
    public String value() ;
}

在以上的Annontation 中定義了一個value ,在以後使用此 Annontation時,可以將內容設置給value .
向Annontation 中設置內容:
代碼:
@MyAnnontation("張三")
class Demo{
    
}

在使用@MyAnnontation 時也可以直接指定接受的參數的屬性名稱。
代碼:
@MyAnnontation(value="張三")
class Demo{
    
}

在@MyAnnontation 中設置多個屬性:
代碼:
package com.zsc.annon;

public @interface MyAnnontation {
    public String key();
    public String value() ;
}

分別設置內容:
@MyAnnontation(value="張三",key="學生")
class Demo{
    
}

在@MyAnnontation 設置數組屬性
代碼:
package com.zsc.annon;
public @interface MyAnnontation {
    public String[] value();
    
}

設置一個數組:
@MyAnnontation(value={"張三","學生"})
class Demo{
    
}

4.3、默認值
如果在一個已經定義好的Annontation 中已經定義了若干屬性,但是在使用Annontation 時並沒有制定具體的內容,則在編譯時也會出現錯誤。此時可以使用默認值。
格式:[public] @interface Annontation名稱{
    數據類型 變量名稱() dafault 默認值;
}
定以一個存在默認值的Annontation
代碼:
package com.zsc.annon;
public @interface MyAnnontation {
    public String key() default "學生";
    public String value() default "張三";
}

這樣的話,在以後調用MyAnnontation 時候沒有設置內容,則會將默認值賦給屬性,而如果已經明確的給出了內容,則將給出的內容賦給屬性。

4.4、通過反射取得 Annontation
如果要讓一個Annontation 起作用,則必須結合反射機制。
4.4.1 取得全部的 Annontation
代碼:
package com.zsc.annon;
public class SimpleDemo {
    @Override
    @SuppressWarnings(value="unchecked")
    @Deprecated
    public String toString(){
        return "hello everyone!" ;
    }
}

代碼2:
package com.zsc.annon;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
public class ReflactTest {
    public static void main(String[] args) throws Exception {
        Class<?> c = null ;
        c = Class.forName("com.zsc.annon.SimpleDemo");
        Method mt = c.getMethod("toString");
        Annotation an[] = mt.getAnnotations();
        for(Annotation a:an){
            System.out.println(a);
        }
    }
}

運行結果:
@java.lang.Deprecated()

SimpleDemo 的toString() 方法雖然使用了3個Annotation 註釋,但是最後真正得到的只能是一個,這是因爲只有Deprecated 使用了 RUNTIME 的方式聲明,所以只有它可以取得。

4.4.2 取得指定的Annotation 中的內容
代碼1:
package com.zsc.annon;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(value=RetentionPolicy.RUNTIME)
public @interface MyAnnotationReflact {
    public String key() default "student";
    public String value() default "zhangsan";
}

代碼2:
package com.zsc.annon;
public class SimpleDemo2 {
    @Override
    @Deprecated
    @SuppressWarnings("unchecked")
    @MyAnnotationReflact(key="worker",value="lisi")
    public String toString(){
        return "hello word !";
    }
}

代碼3:
package com.zsc.annon;
import java.lang.reflect.Method;
public class ReflactTest2 {
    public static void main(String[] args) throws Exception {
        Class<?> c = null ;
        c = Class.forName("com.zsc.annon.SimpleDemo2");
        Method mt = c.getMethod("toString");
        if(mt.isAnnotationPresent(MyAnnotationReflact.class)){
            MyAnnotationReflact mda = null ;
            mda = mt.getAnnotation(MyAnnotationReflact.class);
            String key = mda.key();
            String value = mda.value();
            System.out.println("key:"+key);
            System.out.println("value:"+value);
        }
    }
}

運行結果:
key:worker
value:lisi

總結:從上面可以看到,只要適當的使用反射機制,就可以將Annotation中指定的內容設置到對應的操作中。





發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章