1. 程式人生 > >java 註解詳解+示例

java 註解詳解+示例

註解介紹

  • 1.5開始引入
  • 註解可以理解為一種描述資料的資料,或者可以稱為一種描述元資料的方法。
  • java提供的預設註解:@Override,@Deprecated。
  • 註解僅僅是元資料,和業務邏輯無關
  • 定義方法在 java.lang.annotation包中

元註解

java提供4中元註解來定義我們的註解
1. @Target,
2. @Retention,
3. @Documented,
4. @Inherited

1. @Target,

@Target說明了Annotation所修飾的物件範圍,即用於描述註解的使用範圍
1. CONSTRUCTOR:用於描述構造器
2. FIELD:用於描述域
3. LOCAL_VARIABLE:用於描述區域性變數
4. METHOD:用於描述方法
5. PACKAGE:用於描述包
6. PARAMETER:用於描述引數
7. TYPE:用於描述類、介面(包括註解型別) 或enum宣告
8. ANNOTATION_TYPE:適用於annotation型別,宣告註解型別
9. TYPE_PARAMETER:1.8版本
10. TYPE_USE: 1.8版本

TYPE_PARAMETER和TYPE_USE擴充套件了泛型使用場景,包括泛型、超類和介面實現、甚至是方法的Exception宣告。

2. @Retention

  1. SOURCE:在原始檔中有效(即原始檔保留),在編譯階段丟棄。註解在編譯結束之後就不再有任何意義,所以它們不會寫入位元組碼。比如:@Override
    2.CLASS:在class檔案中有效(即class保留)。在類載入的時候丟棄。在位元組碼檔案的處理中有用。註解預設使用這種方式。
    3.RUNTIME:在執行時有效(即執行時保留)。 始終不會丟棄,執行期也保留該註解,因此可以使用反射機制讀取該註解的資訊比。如:@Deprecated。比如Srping中的@Autowired,@ResponseBody等都屬於這一類。

表示需要在什麼級別儲存該註釋資訊,用於描述註解的生命週期

3. @Inherited

介紹
元註解是一個標記註解,@Inherited闡述了某個被標註的型別是被繼承的。如果一個使用了@Inherited修飾的annotation型別被用於一個class,則這個annotation將被用於該class的子類。

使用此註解宣告出來的自定義註解,在使用此自定義註解時,如果註解在類上面時,子類會自動繼承此註解,否則的話,子類不會繼承此註解。這裡一定要記住,使用Inherited宣告出來的註解,只有在類上使用時才會有效,對方法,屬性等其他無效。

4. @Documented

一個簡單的Annotations標記註解,表示是否將註解資訊新增在java文件中。

表明這個註解應該被 javadoc工具記錄. 預設情況下,javadoc是不包括註解的。

示例:
在某個方法上增加了有Documented註解的元註解,則javadoc命令生成xxx.html檔案中。可以看到該註解。

註解元素

註解類中定義的元素稱為註解元素,註解元素可用的型別如下:
- 所有基本資料型別(int,float,boolean,byte,double,char,long,short)
- String型別
- Class型別
- enum型別
- Annotation型別
- 以上所有型別的陣列

實際使用注意問題

1. 使用註解不使用名字時,賦值規則,

  • 如果註解只有一個屬性,那麼肯定是賦值給該屬性。

  • 如果註解有多個屬性,而且前提是這多個屬性都有預設值,那麼你不寫註解名賦值,會賦值給名字為“value”這屬性。

  • 如果註解有多個屬性,其中有沒有設定預設值的屬性,那麼當你不寫屬性名進行賦值的時候,是會報錯的。

2. 若註解中定義了多個註解元素,除非註解元素使用的default。否則在使用該註解時,都需要賦值。

示例

1. 變數上的註解

1.1 註解定義

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface FieldAnno {
    public String fileName() default "defaultFileName";
    public int value();

}
1.2 使用
public class MyAnno {
    @FieldAnno(111)
    private String myStr;
    ...
}    
1.3 呼叫 
 /**
     * 根據欄位名
     */
    public static void getFieldAnno() {
        try {
            Field myfiel = MyAnno.class.getDeclaredField("myStr");
//            myfiel.setAccessible(true);
            FieldAnno fieldAnno = myfiel.getAnnotation(FieldAnno.class);
            if (fieldAnno != null) {
                System.out.println("----getFieldAnno----");
                System.out.println(fieldAnno.fileName());
                System.out.println(fieldAnno.value());
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }

     /**
     * 搜尋所有欄位
     */
    public static void getFieldAnno2() {

        Field[] fields = MyAnno.class.getDeclaredFields();
        for (Field field : fields) {
            if (field.isAnnotationPresent(FieldAnno.class)) {
                FieldAnno fieldAnno = field.getAnnotation(FieldAnno.class);
                System.out.println("----getFieldAnno2----");
                System.out.println(fieldAnno.fileName());
                System.out.println(fieldAnno.value());
            }
        }


    }

2. 一般方法上的註解

2.1 定義
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface MethodAnno {
    String methodNamett();
}
2.2 使用
@MethodAnno(methodNamett = "mycustomerMethod")
    private static void myMethod(){

    }
2.3 呼叫
 /**
     * 根據方法名獲取
     */
    public static void getMethodAnno() {
        try {

            Method myMethod = MyAnno.class.getDeclaredMethod("myMethod", MyAnno.class.getClasses());
            MethodAnno methodAnno = myMethod.getDeclaredAnnotation(MethodAnno.class);

            System.out.println(methodAnno.methodNamett());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }

    /**
     * 查詢所有方法
     */
    public static void getMethodAnno2() {
        Method[] myMethods = MyAnno.class.getMethods();

        for (Method method : myMethods) {
            if(method.isAnnotationPresent(MethodAnno.class)){
                MethodAnno methodAnno = method.getDeclaredAnnotation(MethodAnno.class);
                System.out.println(methodAnno.methodNamett());
            }
        }

    }

3. 構造方法上的註解

3.1 定義

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.CONSTRUCTOR)
public @interface ConstructorAnno {

    boolean isDefault();
}

3.2 使用
@ConstructorAnno(isDefault = true)
    public MyAnno() {
    }

    @ConstructorAnno(isDefault = false)
    public MyAnno(String name) {
    }
3.3 呼叫
 /**
     * 根據指定名稱獲取
     */
    public static void getConAnno() {
        try {
            Constructor defaultConstructor = MyAnno.class.getDeclaredConstructor();
            ConstructorAnno constructorAnno=defaultConstructor.getDeclaredAnnotation(ConstructorAnno.class);
            System.out.println(constructorAnno.isDefault());

            Constructor Constructor = MyAnno.class.getDeclaredConstructor(String.class);
            ConstructorAnno constructorAnno2=Constructor.getDeclaredAnnotation(ConstructorAnno.class);
            System.out.println(constructorAnno2.isDefault());
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

    }

    /**
     * 搜尋所有構造方法
     */
    public static void getConsAnno2() {
        Constructor[] myConstructors = MyAnno.class.getConstructors();

        for (Constructor constructor : myConstructors) {
            if (constructor.isAnnotationPresent(ConstructorAnno.class)) {
                ConstructorAnno constructorAnno = constructor.getDeclaredAnnotation(ConstructorAnno.class);
                System.out.println(constructorAnno.isDefault());
            }
        }
    }

4. 類上的註解

4.1 定義
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)//可以修飾class 和inteface
public @interface TypeAnno {
    String type();
}
4.2 使用
@TypeAnno(type="myTypeAnno")
public class MyAnno {
}
4.3 呼叫
  /**
     * 根據類名查詢該類的
     */
    public static void getTypeAnno() {

        TypeAnno typeAnno = MyAnno.class.getDeclaredAnnotation(TypeAnno.class);
        System.out.println(MyAnno.class.isAnnotationPresent(TypeAnno.class));
        System.out.println(typeAnno.type());

    }

    /**
     * 查詢包名下所有類
     */
    public static void getAnnoTypeAnno() {
        String basePackage = "com.myannotation";
        try {
            //先找到資源
            Enumeration<URL> enums = Thread.currentThread().getContextClassLoader().getResources(basePackage.replace(".", "/"));
            while (enums.hasMoreElements()) {
                URL uri = enums.nextElement();
                if ("file".equals(uri.getProtocol())) {//是否是檔案協議的檔案
                    String dirsStr = uri.getFile();//獲取檔案路徑
                    File dirsFile = new File(dirsStr);//建立File的資料夾物件
                    if (dirsFile.isDirectory()) {
                        File[] files = dirsFile.listFiles();//獲取該資料夾下所有檔案
                        for (File file : files) {
                            if (file.isFile()) {
                                String classname = basePackage + "." + file.getName();
                                classname = classname.substring(0, classname.length() - 6);
//                                System.out.println(classname);
                                Class clazz = Class.forName(classname);
                                if (clazz.isAnnotationPresent(TypeAnno.class)) {
                                    TypeAnno typeAnno = (TypeAnno) clazz.getDeclaredAnnotation(TypeAnno.class);
                                    System.out.println(typeAnno.type());
                                }
                            }
                        }
                    }
                }
            }

        } catch (IOException e) {
            e.printStackTrace();
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        }
    }

5. 區域性變數的註解

public void m(int a)  
@MyOwnAnnotation(some information)  
int b = 5;  
}

6. 引數上的註解

6.1 定義
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.PARAMETER)
public @interface  ParamAnno {
    String value() ;
}
6.2 使用
public static void meMethod(@ParamAnno("myvalue") String name1,String name2){
        @LocalVariableAnno()
        String tt;
    }
6.3 呼叫
 public static void getParamAnno() {
        try {
            Method method = MyAnno.class.getDeclaredMethod("meMethod", String.class, String.class);
            Annotation[][] paramss = method.getParameterAnnotations();
            for (Annotation[] parameterAnnotation : paramss) {
                for (Annotation annotation : parameterAnnotation) {
                    if (annotation instanceof ParamAnno) {
                        ParamAnno param = (ParamAnno) annotation;
                        System.out.println(param.value());
                    }
                }
            }
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }

    }

7. 包註解

作用
1、為標註在包上Annotation提供便利;
2、宣告包的私有類和常量;
* 3、提供包的整體註釋說明

8. ANNOTATION_TYPE

待續

9. TYPE_PARAMETER和TYPE_USE

Spring中使用的註解

AliasFor

給註解起別名。

參考