java中的註解

前言:

最近作項目時發現Spring框架運用了大量自定義註解,因此回過頭來有必要深刻了解和整理關於註解的知識。java

註解是java在1.5版本引入的新特性,隨後一些開源組件也引入此項特性,如Spring,Hibernate,Mybatis。JPA規範更是全註解式程序員

的。如下用到的示例代碼均來自於<<Java編程思想第四版>>。編程

一.什麼是註解

註解也被稱爲元數據。咱們能夠在代碼中添加信息,而後能夠在須要的時候使用這些數據。經過在源代碼級別保存註解,使得代碼變得整潔便於維護。註解是語言級別的概念,享有編譯期的類型檢查保護。使用擴展的annotationAPI或者字節碼工具類庫,程序員擁有對源代碼以及字節碼強大的檢查和操做能力。
數組

二.定義註解

1.基本語法
框架

import java.lang.annotation.*;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Test {}

沒有元素的註解稱爲標記註解(marker  annotation),如以上定義的@Test,下面定義了一個包含兩個元素的註解:
ide

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UseCase {
  public int id();
  public String description() default "no description";
}

2.元註解工具

元註解負責註解其餘註解。Java內置了四種元註解:
測試

@Target

表示該註解能夠用於什麼地方。可能的ElementType參數包括:ui

CONSTRUCTOR:構造器的聲明spa

FIELD:域聲明(包括enum實例)

LOCAL_VARIABLE:局部變量聲明

METHOD:方法聲明

PACKAGE:包生明VM

PARAMETER:參數聲明

TYPE:類、接口(包括註解類型)或enum聲明

@Retention

表示須要在生麼級別保存該註解信息。可選的RetentionPolicy參數包括: 

SOURCE:註解將被編譯器丟棄。

CLASS:註解在class文件中可用,但會被VM丟棄。

RUNTIME: VM將在運行期也保留註解,所以能夠經過反射機制讀取註解的信息。

@Documented 將此註解包含在Javadoc中。
@Inherited 容許子類繼承父類中的註解。

3.基本註解

Java同時內置了三種基本註解:

@Override 表示當前的方法定義將覆蓋超類中的方法

@Deprecated 若是使用了註解爲它的元素,編譯器會發出警告信息

@SuppressWarnings 關閉編譯器警告信息

4.註解中的元素

註解中的元素可用類型有:全部基本類型(int,float,boolean等),不容許包裝類型,String,Class,enum,Annotation,以上類型的數組

默認值限制

  1. 註解中的元素不能有不肯定的值。要麼具備默認值,要麼在使用註解時提供元素的值。

  2. 對於非基本類型的元素,不管是在使用註解時,仍是在定義註解並設定元素默認值時,都不能爲null。

註解不支持繼承: 即不能使用關鍵字extends來繼承某個@interface。

三.使用註解

 下面的PasswordUtils類中有三個方法使用了@UseCase

import java.util.List;

public class PasswordUtils {
  @UseCase(id = 47, description =
  "Passwords must contain at least one numeric")
  public boolean validatePassword(String password) {
    return (password.matches("\\w*\\d\\w*"));
  }
  @UseCase(id = 48)
  public String encryptPassword(String password) {
   return new StringBuilder(password).reverse().toString();
  }
  @UseCase(id = 49, description =
  "New passwords can't equal previously used ones")
  public boolean checkForNewPassword(
    List<String> prevPasswords, String password) {
    return !prevPasswords.contains(password);
  }
}
四.註解處理器

下面是一個簡單的註解處理器,它讀取PassWordUtils類,並使用反射機制查找@UseCase標記。提供一組id值用於測試,它會列出找到的用例和缺失的用例。

import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;

public class UseCaseTracker {
  public static void trackUseCases(List<Integer> useCases, Class<?> cl) {
    for(Method m : cl.getDeclaredMethods()) {
      UseCase uc = m.getAnnotation(UseCase.class);
      if(uc != null) {
        System.out.println("Found Use Case:" + uc.id() + " " + uc.description());
        useCases.remove(new Integer(uc.id()));
      }
    }
    for(int i : useCases) {
      System.out.println("Warning: Missing use case-" + i);
    }
  }
  public static void main(String[] args) {
    List<Integer> useCases = new ArrayList<Integer>();
    Collections.addAll(useCases, 47, 48, 49, 50);
    trackUseCases(useCases, PasswordUtils.class);
  }
} 

/* Output:
Found Use Case:47 Passwords must contain at least one numeric
Found Use Case:48 no description
Found Use Case:49 New passwords can't equal previously used ones
Warning: Missing use case-50
*/
相關文章
相關標籤/搜索