概述
註解(Annotation),也叫元數據。一種代碼級別的說明。它是JDK1.5及以後版本引入的一個特性,與類、接口、枚舉是在同一個層次。它可以聲明在包、類、字段、方法、局部變量、方法參數等的前面,用來對這些元素進行說明,註釋。
作用:
1. 編寫文檔:通過代碼裏標識的元數據生成文檔【生成文檔doc文檔】
2. 代碼分析:通過代碼裏標識的元數據對代碼進行分析【使用反射】
3. 編譯檢查:通過代碼裏標識的元數據讓編譯器能夠實現基本的編譯檢查【Override】
註解介紹:
jdk內置註解:
在java.lang包下,JAVA提供了5個基本註解:
@Override
限定重寫父類方法。對於子類中被@Override 修飾的方法,如果存在對應的被重寫的父類方法,則正確;如果不存在,則報錯。@Override 只能作用於方法,不能作用於其他程序元素。
@Deprecated
用於表示某個程序元素(類、方法等)已過時。如果使用了被@Deprecated修飾的類或方法等,編譯器會發出警告。
@SuppressWarnings
抑制編譯器警告。指示被@SuppressWarnings修飾的程序元素(以及該程序元素中的所有子元素,例如類以及該類中的方法…..)取消顯示指定的編譯器警告。例如,常見的@SuppressWarnings(”unchecked”)
SuppressWarnings註解的常見參數值的簡單說明:
1、deprecation:使用了不贊成使用的類或方法時的警告(使用@Deprecated使得編譯器產生的警告);
2、unchecked:執行了未檢查的轉換時的警告,例如當使用集合時沒有用泛型 (Generics) 來指定集合保存的類型; 關閉編譯器警告
3、allthrough:當 Switch 程序塊直接通往下一種情況而沒有 Break 時的警告;
4、path:在類路徑、源文件路徑等中有不存在的路徑時的警告;
5、serial:當在可序列化的類上缺少 serialVersionUID 定義時的警告;
6、finally:任何 finally 子句不能正常完成時的警告;
7、all:關於以上所有情況的警告。
@SafeVarargs
@SafeVarargs是JDK 7 專門爲抑制“堆污染”警告提供的。
元註解說明:
點擊jdk自帶註解(SuppressWarnings)查看源碼如下:
package java.lang;
import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
String[] value();
}
通過源碼我們發現@Target()和@Retention()兩個註解爲定義註解SuppressWarings使用的註解,我們稱這兩個爲元註解。
通過我們查jdk文檔發現,jdk常用的註解爲四個,這四個註解的功能和使用說明如下表:
名稱 | 值 | 說明 |
---|---|---|
@Target | ElementType.METHOD(更多值見下面ElementType類) | 指定註解的作用域,class存在於類和接口上,Field作用於變量,Method作用於方法。 |
@Retention | RetentionPolicy.RUNTIME (更多值見下面ElementType類) | 指定註解的存在週期,Source註解信息只在源碼中存在;Class註解信息存在源碼,字節碼;RunTime註解信息存在源碼,字節碼,和運行時。 |
@Inherited | 無 | 指定該註解在父類使用的時候,子類會繼成該註解。 |
@Documented | 無 | 該註解表明這個註解應該被 javadoc工具記錄. 默認情況下,javadoc是不包括註解的. 但如果聲明註解時指定了 @Documented,則它會被 javadoc 之類的工具處理, 所以註解類型信息也會被包括在生成的文檔中. |
jdk1.8 ElemenType枚舉類
public enum ElementType {
/** Class, interface (including annotation type), or enum declaration */
TYPE,
/** Field declaration (includes enum constants) */
FIELD,
/** Method declaration */
METHOD,
/** Formal parameter declaration */
PARAMETER,
/** Constructor declaration */
CONSTRUCTOR,
/** Local variable declaration */
LOCAL_VARIABLE,
/** Annotation type declaration */
ANNOTATION_TYPE,
/** Package declaration */
PACKAGE,
/**
* Type parameter declaration
*
* @since 1.8
*/
TYPE_PARAMETER,
/**
* Use of a type
*
* @since 1.8
*/
TYPE_USE
}
RetentionPolicy 類源碼
package java.lang.annotation;
public enum RetentionPolicy {
/**
* Annotations are to be discarded by the compiler.
*/
SOURCE,
/**
* Annotations are to be recorded in the class file by the compiler
* but need not be retained by the VM at run time. This is the default
* behavior.
*/
CLASS,
/**
* Annotations are to be recorded in the class file by the compiler and
* retained by the VM at run time, so they may be read reflectively.
*
* @see java.lang.reflect.AnnotatedElement
*/
RUNTIME
}
自定義註解:
自定義註解類編寫的一些規則:
1. Annotation型定義爲@interface, 所有的Annotation會自動繼承java.lang.Annotation這一接口,並且不能再去繼承別的類或是接口。
2. 參數成員只能用public或默認(default)這兩個訪問權修飾。
3. 參數成員只能用基本類型byte,short,char,int,long,float,double,boolean八種基本數據類型和String、Enum、Class、annotations等數據類型,以及這一些類型的數組.。
4. 註解也可以沒有定義成員。
自定義註解需要使用到元註解,獲取註解信息可以通過APT(Annotation Processing Tool)獲取。在jdk中也可以通過反射獲取@Retention爲RetentionPolicy.RUNTIME(運行期間)的註解信息。
反射獲取註解信息:
自定義註解:RStudent.java
package anno;
import static java.lang.annotation.ElementType.TYPE;
import static java.lang.annotation.RetentionPolicy.RUNTIME;
import java.lang.annotation.Documented;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
@Documented
@Retention(RUNTIME)
@Target(TYPE)
public @interface RStudent {
int _id() default 0;
String _name() default "";
String _address() default "";
}
javaBean文件:
package model;
import anno.RStudent;
@RStudent(_id =1,_name="zhangwenwen",_address="beijing")
public class Student {
public int id;
public String name;
public String address;
}
測試代碼:
package main;
import java.lang.annotation.Annotation;
import java.lang.reflect.Constructor;
import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import model.Student;
/**
*
* @author 53048
*
*/
public class TestReflection {
public static void main(String args []){
//反射獲取註解
testAnno(Student.class);
}
private static <T> void testAnno(Class<T> classs) {
// TODO Auto-generated method stub
System.out.println("------------------------------------------------------------------------");
System.out.println("測試註解:");
T object = null;
try {
object = classs.newInstance();
} catch (InstantiationException e) {
// TODO Auto-generated catch block
e.printStackTrace();
} catch (IllegalAccessException e) {
// TODO Auto-generated catch block
e.printStackTrace();
}
Annotation[] annos = classs.getDeclaredAnnotations();
for(Annotation anno:annos){
System.out.println(anno);
if(anno instanceof RStudent){
RStudent students = (RStudent)anno;
Student stu= (Student)object;
stu.id = students._id();
stu.address = students._address();
stu.name = students._name();
System.out.println("學生的Id:"+stu.id);
System.out.println("學生的name:"+stu.name);
System.out.println("學生的address:"+stu.address);
}
}
}
希望對您有所幫助!