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
- 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
給註解起別名。