從JDK5開始,Java增加了對元數據的支持,也就是Annotation,它也被稱作註釋。
基本的Annotation:
限定重寫父類方法:@Override
@Override就是用來指定方法的重寫,它強制一個子類必須覆蓋父類的方法,這個大家比較熟悉就不多說了。
已過時的標記:@Deprecated
如果你的程序元素被標記成Deprecated的話,那麼你在調用的時候該程序元素就會被加線,證明該方法過時,不建議被使用。
public class TestDeprecate {
@Deprecated
public void sayHello() {
System.out.println("Hello");
}
public void sayWorld() {
sayHello();
}
}
抑制編譯器的警告:@SuppressWarnings
如果你想取消顯示指定的編譯器警告的話,就可以用該Annotation,最常見的是在泛型上,下面就舉這個例子:
@SuppressWarnings(value="unchecked")
public class TestSuppressWarnings {
public static void main(String[] args) {
List<String> list = new ArrayList();
}
}
這樣就取消了沒有使用泛型的警告。
自定義Annotation:
定義一個新的Annotation類型要使用@interface關鍵字,下面就是一個簡單的Annotation類型:
public @interface Hello {
}
當然自定義的Annotation還可以帶成員變量,它的成員變量在Annotation定義一無形參的方法形式來聲明的,其方法名和返回值定義了該成員變量的名字和類型:
public @interface Hello {
String name();
int age();
}
簡單的實際應用:
public class World {
@Hello(name="guo", age=20)
public void say() {
System.out.println("World");
}
}
通過簡單的key=value形式就給成員變量賦值了
當然自定義的Annotation的成員變量可以設定默認值:
public @interface Hello {
String name() default "guo";
int age() default 20;
}
提取Annotation信息:
被Annotation修飾的程序元素我們可以根據Annotation提取出裏面的信息:
下面先介紹=幾個方法:
getAnnotation(Class<T> annltationClass):返回該程度元素上存在的指定類型的註釋,如果該類的註釋不存在就返回null
Annotation[] getAnnotations():返回該程序元素上存在的所有註釋
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass):判斷該程序上元素上是否存在指定類型的註釋,如果存在即true,否則false
下面我們用反射的知識去幫助提取出相應的信息:
public class World {
@Hello(name="guo", age=20)
public void say() {
System.out.println("World");
}
public static void main(String[] args) {
try {
Annotation[] annotation = Class.forName("com.xujianguo.annotation.World").getMethod("say").getAnnotations();
for(Annotation a : annotation) {
System.out.println(a.toString());
if(a instanceof Hello) {
System.out.println("-------------------");
System.out.println(((Hello)a).name());
System.out.println(((Hello)a).age());
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
這裏要嚴重提醒的是:如果要用反射就拿Annotation的信息的話,就可以在定義的Annotation上加上@Retention:
@Retention(value=RetentionPolicy.RUNTIME)
public @interface Hello {
String name() default "guo";
int age() default 20;
}
這樣保證了在JVM會保留該Annotation,就可以通過反射獲取信息了。
先面模擬一下Junit的單元測試:
定義@TestSimulation這個新的Annotation:
@Retention(value=RetentionPolicy.RUNTIME)
public @interface TestSimulation {
}
在Communication類中應用@TestSimulation:
public class Communication {
@TestSimulation
public void say() {
System.out.println("hello");
}
public void call() {
System.out.println("call you");
}
@TestSimulation
public void look() {
System.out.println("look");
}
}
定義工具類解析:
public class AnnotationUtil {
public static void processAnnotation(String path) {
try {
Class clazz = Class.forName(path);
Object o = clazz.newInstance();
Method[] methods = clazz.getMethods();
for(Method m : methods) {
if(m.isAnnotationPresent(TestSimulation.class)) {
m.invoke(o);
}
}
} catch (Exception e) {
e.printStackTrace();
}
}
}
測試類:
public class StartUp {
public static void main(String[] args) {
AnnotationUtil.processAnnotation("com.xujianguo.annotation.Communication");
}
}
測試結果:
hello
look