java_notation.htmljavascript
是Java代碼中的元數據, 在建立以後的某個時刻能夠使用, 表明了代碼的配置信息, 代碼和配置結合在一塊兒, 存儲有關程序的額外信息.php
註解的定義相似interface的定義, 同其餘Java接口同樣, 註解也會被編譯成class文件. 格式爲:css
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.Runtime)
public @interface Test{
///
public int id();
public String descripteion() default "no description";
}
其中, @Target
和 @Retention
也是註解被稱爲元註解, 是Java提供的四種註解,後面會補充.@Target
表明了該註解應用的對象(如一個類或者一個函數).@Retention
表明了該註解在哪個級別可用(共三種: 源碼中Source, 類文件Class, 運行時Runtime).
通常的註解中會有元素, 元素的定義相似於接口中方法的定義(成員變量相似接口的方法的定義). 可是後面能夠跟一個default指定默認值.
沒有元素的註解稱之爲標記註解, 如元註解中的 @Documented
註解的元素使用時是以名-值對的形式定義的, 並放在註解後的括號內, 如@Test( id = 49, desctiption = "lyb" )
.html
元註解是Java源碼中定義的四種註解, 本身定義的註解必然要藉助這四種註解.java
註解 | 解釋 |
---|---|
@Target | 表示該註解能夠用於什麼地方, 接受的參數爲ElementType參數, 共有如下幾種類型: CONSTRUCTOR: 構造器的聲明 FIELD: 域聲明(包括enum實例) LOCAL_VARIABLE: 局部變量聲明 METHOD: 方法聲明 PACKAGE: 包聲明 PARAMETER: 參數聲明 TYPE: 類, 接口(包括註解類型)或enum聲明 |
@Retention | 表示須要在什麼級別保存該註釋信息, 接受參數爲RetentionPolicy類型: SOURCE: 註解將被編譯器丟棄 CLASS: 註解在class文件中可用,可是會被編譯器丟棄 RUNTIME: VM將在運行期也保留註解, 所以能夠經過反射機制讀取註解的信息 |
@Documented | 將此註解包含在Javadoc中 |
@Inherited | 容許子類繼承父類中的註解 |
元註解自己的定義也是依賴元註解的, 相似於遞歸.
如 @Target
的源碼:node
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
/** * Returns an array of the kinds of elements an annotation type * can be applied to. * @return an array of the kinds of elements an annotation type * can be applied to */
ElementType[] value();
}
註解和註釋的區別: 若是沒有處理註解的工具, 那麼註解不會比註釋更有用. 因此使用註解就是要有相應的註解處理器, 而註解處理器是創建在反射機制上的.nginx
對以VM, 在沒有註解處理器的狀況下, 有沒有註解對於源代碼編譯獲得的字節嗎應該是同樣的, 固然可能會多出註解的字節碼.git
下面給出一個例子:github
註解UserCase:web
package test;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/** * Created by lyb on 16-11-29. */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface UserCase {
public int id();
public String description() default "no description";
}
使用了註解的通常類:
package test;
import java.util.List;
/** * Created by lyb on 16-11-29. */
public class PasswordUtil {
@UserCase(id = 47, description = "Passwords must contains at last one numberic")
public boolean validatePassword(String password){
return password.matches("\\w*\\d\\w*");
}
@UserCase(id = 48)
public String encryptPassword(String password){
return new StringBuilder(password).reverse().toString();
}
@UserCase(id = 50, description = "New passwords can't equals the used one")
public boolean checkForNewPassword(List<String> prevPassword, String password){
return !prevPassword.contains(password);
}
}
真正的註解處理器:
package test;
import java.lang.reflect.Method;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
/** * Created by lyb on 16-11-29. */
public class UserCaseTracker {
public static void trackUserCases(List<Integer> userCases, Class<?> cl){
for (Method m : cl.getDeclaredMethods()){
UserCase uc = m.getAnnotation(UserCase.class);
if (uc != null){
System.out.println("Found user case : " + uc.id()
+ " " + uc.description());
userCases.remove(new Integer(uc.id()));
}
}
for (int i : userCases){
System.out.println("Warning: Missing user case !");
}
}
public static void main(String[] args){
List<Integer> userCases = new ArrayList<>();
Collections.addAll(userCases, 47, 48, 49, 50);
trackUserCases(userCases, PasswordUtil.class);
}
}
程序的輸出:
Found user case : 47 Passwords must contains at last one numberic Found user case : 48 no description Found user case : 50 New passwords can't equals the used one Warning: Missing user case-49!
須要注意的地方,
傳給反射的參數是class類型的.
由於@UserCase
修飾的是Method, 因此經過Method獲得註解對象.
即在註解的interface中定義的相似函數的元素, 如int的id(), String的description().
全部可用的註解元素的類型有:
須要注意的是:
對註解元素的限制:
註解中的元素都必須肯定, 或者有默認值, 或者在註解中賦值.
非基本類型(如本身定義的類)的值不能有null, 所以必須本身定義一些特殊值來表示某個元素不存在.
使用多個註解的時候, 同一個註解不能重複使用.
註解自己不支持繼承, 可是被 @Inherited
修飾的類具備繼承性. 一樣地, 因爲沒有繼承性, 所以要具備相似多態的註解, 就必須多定義不一樣參數的函數或者是類, 而且用反射函數 getDeclaredAnnotation()
來遍歷獲得須要的註解.
generated by haroopad