1. 程式人生 > >註解的使用和自定義註解

註解的使用和自定義註解

JDK中的三個基本註解

a、@Override:檢查子類確實是覆蓋了父類的方法。
b、@Deprecated:說明已經過時了。
c、@SuppressWarnings({ "unused", "deprecation" }):抑制程式中的警告。unused警告的型別。{}陣列。all抑制所有警告。

簡單使用:

public class Demo1 {

    //@SuppressWarnings({ "deprecation", "unused" })
    @SuppressWarnings("all")
    public void fun()
    {
        int
i = 5; System.out.println("hello"); System.out.println(new Date().toLocaleString()); } } class Tests extends Demo1 { @Override public void fun() { super.fun(); } @Deprecated public void tt() { System.out.println(new Date().toLocaleString()); } }

宣告一個註解 @interface 註解名{}
public @interface MyAnnotation{}

註解它的本質就是一個介面,這個介面需要繼承 Annotation介面。

public interface MyAnnotation extends java.lang.annotation.Annotation {
}

註解的屬性型別:

    1.基本型別
    2.String
    3.列舉型別
    4.註解型別
    5.Class型別
    6.以上型別的一維陣列型別

具體是怎樣定義的呢,我們看程式碼:

public @interface
MyAnno1 { //註解中定義的都是屬性 int age() default 20; String[] name() default "hehe"; String value() default "haha"; Love love(); //MyAnno2 anno(); //public static final int num = 5;//可以 //public abstract void fun();//error }

使用自定義註解:

public class Demo2 {

    //@MyAnno1(age=25,name={"jack","lucy"},value="zhengzhi")
    //@MyAnno1(value="zhengzhi")
    @MyAnno1(value="zhengzhi",love=Love.eat)
    public void tests()
    {

    }

}

如果在沒有預設值的情況下,使用自定義註解我們需要設定註解中屬性的值。

註解的反射:(靈魂)

模擬Junit的@Test

a、反射註解類
java.lang.reflect.AnnotatedElement:
<T extends Annotation> T getAnnotation(Class<T> annotationType):得到指定型別的註解引用。沒有返回null。
Annotation[] getAnnotations():得到所有的註解,包含從父類繼承下來的。
Annotation[] getDeclaredAnnotations():得到自己身上的註解。


boolean isAnnotationPresent(Class<? extends Annotation> annotationType):判斷指定的註解有沒有。

ClassMethodFieldConstructor等實現了AnnotatedElement介面.
如果:Class.isAnnotationPresent(MyTest.class):判斷類上面有沒有@MyTest註解;
Method.isAnnotationPresent(MyTest.class):判斷方法上面有沒有@MyTest註解。

下面通過程式碼實現一下。
我們模擬實現@Test註解的功能
首先這是我們的註解@MyTest

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
//元註解: 用來註解註解的
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
    long timeout() default Integer.MAX_VALUE;//設定超時時間的
}

這是我們使用註解的類:

public class DBCRUD {

    @MyTest(timeout=1000000)
    public void addTest()
    {
        System.out.println("addTest方法執行了");
    }

    @MyTest
    public void updateTest()
    {
        System.out.println("updateTest方法執行了");
    }

}

當我們使用了註解,我們就需要判該類是否使用了註解,我們通過反射來實現。

private static void method1() throws IllegalAccessException,
            InvocationTargetException, InstantiationException {

        Class claz = DBCRUD.class;//得到位元組碼檔案物件

        //得到該類及父類中的所有方法
        Method[] methods = claz.getMethods();

        for(Method m:methods){
            //判斷方法是否使用了@MyTest這個註解
//          boolean boo = m.isAnnotationPresent(MyTest.class);
//          System.out.println(m.getName()+"===="+boo);//都是false 預設註解存活到 CLASS,改變存活到RUNTIME
            if(m.isAnnotationPresent(MyTest.class)){
                m.invoke(claz.newInstance(), null);
            }
        }
    }

**這裡我們需要注意的是,我們需要考慮到自定義註解的存活範圍。
預設的自定義註解只存活到編譯時期,class階段。

可以注意到,我們上面的自定義註解應用了@Retention註解,這個註解就是改變自定義註解的存活範圍。

這個註解也叫做元註解,只能用在註解上的註解叫做元註解。
**
上面的method方法沒有考慮到超時的問題,下面我們再完善一下。

//method1();
        //反射解析註解的屬性
        Class claz = DBCRUD.class;

        Method[] methods = claz.getMethods();

        for(Method m:methods){
            //從該方法上獲取MyTest註解
            MyTest mt = m.getAnnotation(MyTest.class);
            if(mt!=null){
                //得到註解中的屬性
                long out = mt.timeout();
                long start = System.nanoTime();
                m.invoke(claz.newInstance(), null);
                long end = System.nanoTime();
                if((end-start)>out)
                {
                    System.out.println("執行超時");
                }
            }

        }