J2SE 5.0通過引入注釋(Annotation)的概念添加了對元數(shù)據(jù)的支持。
一個(gè)@xxx形式的注釋可以當(dāng)成一個(gè)修飾符來使用,它可以放在任何一個(gè)修飾符可以出現(xiàn)的地方。public,static,final都是java語言的修飾符,注釋可以寫在它們可以出現(xiàn)的任何地方。
舉個(gè)例子,可以看下面一段代碼:
public class AnnotationExample {
public @Override int hashCode() {
return super.hashCode();
}
}
|
在這個(gè)例子中我們使用了一個(gè)java語言API中已經(jīng)有定義的注釋@Override,通過在方法hashCode()中使用這個(gè)注釋,說明了hashCode是一個(gè)覆蓋了父類方法的方法。
至于注釋的具體含義我們在以后部分會說明。
如果你想使用一個(gè)類,你必須首先找到它的定義,或者你自己對它進(jìn)行定義。注釋也是需要定義的,隨便在代碼中插入一個(gè)@XXX之類的注釋是不能夠通過編譯的。
一個(gè)最簡單的Annotation定義類似于接口的定義,就象下面的代碼:
public @interface Info {
}
|
正如你所看到的,里面什么都沒有,但是即使是這樣,我們也可以在程序里使用它:
public @Info String information;
|
這樣的一種什么都沒有定義的空注釋我們稱為標(biāo)記注釋(marker annotations)。
我們可以在其中添加一個(gè)成員的定義:
public @interface Info {
String author();
}
|
這里值得注意的一點(diǎn)是,注釋類中方法的定義不能是私有的,如果你不在前面加public關(guān)鍵字,編譯器會默認(rèn)為它是公有的。
在添加上author的定義后,原來那種只寫了一個(gè)@Info的注釋就必須修改了,之后的注釋必須這樣寫:
public @Info(author="myname") void afunction() {
}
|
一個(gè)注釋的成員可以有默認(rèn)值:
public @interface Info {
String author() default "myname";
}
|
使用默認(rèn)值有什么好處呢?我們可以重新這樣寫了:
public @Info void afunction() {
}
|
在做標(biāo)記時(shí),如果確認(rèn)某個(gè)成員的值和它的默認(rèn)值相同,我們就可以忽略它,而不必顯式地給每個(gè)成員賦值,這樣就減輕了代碼量。
如果我們添加的這個(gè)成員名字叫做value的話,也就是:
public @interface Info {
String value();
}
|
就有了另外一種注釋的用法: 我們可以直接寫出這樣的注釋@Info(“information”),而不必寫@Info(value=”information”),括號里的值會自動傳遞給value。這樣的一種注釋稱為單一值注釋(Single-value annotations)
一個(gè)注釋可以有很多類型不同的成員,這樣的一種注釋稱為完整注釋(full annotations)。
一個(gè)注釋中的成員類型只能夠是原生類型,字符串,Class類型,注釋類型,枚舉類型,或者一維數(shù)組。
假設(shè)我們現(xiàn)在有一個(gè)注釋定義:
public @interface Company {
String value();
}
|
現(xiàn)在我們希望定義另外一個(gè)注釋,這個(gè)注釋類型反映了一個(gè)人的信息:
public @interface Person {
public enum Gender{MALE,FEMALE};
String name();
int age();
Company company();
Gender gender() default Gender.MALE;
String description() default "";
}
|
在程序代碼中添加這種類型的注釋時(shí)可以這么寫:
@Person(age=23,name="MyName",gender=Person.Gender.FEMALE, company=@Company("Foo Corporation"))
|
在java.lang包中定義了三種注釋,分別是:
n Deprecated:和過去javadoc中@deprecated含義相同
n Override:表示方法覆蓋了父類中的方法
n SuppressWarnings:使用這個(gè)注釋可以使編譯器忽略特定類型的警告信息
具體含義可以參照api文檔。
我們知道,注釋的引入,為java語言添加了元數(shù)據(jù)的表達(dá)方式,而元數(shù)據(jù)就是關(guān)于數(shù)據(jù)的數(shù)據(jù)。在java中,還有關(guān)于注釋的注釋,我們相應(yīng)的稱之為元注釋(meta-annotations)
在java中,我們可以使用4種預(yù)先定義的注釋對注釋定義進(jìn)行注釋,這4種注釋是:
n Target:指明注釋可以在哪些代碼段中使用,以避免對注釋的誤用。
n Retention:說明編譯器在編譯和運(yùn)行時(shí)是否忽略該種注釋
n Documented:說明注釋是否出現(xiàn)在Javadoc中

n Inherited:當(dāng)我們在一個(gè)類中使用了某種注釋,有時(shí)候會希望將來它的所有子類中都包含有該種注釋信息,如果在注釋定義中添加了@Inherited,那么這種注釋就會被調(diào)用者的子類繼承
當(dāng)我們在一個(gè)類中使用注釋定義了一系列的元數(shù)據(jù)之后,我們應(yīng)該如何獲取這些元數(shù)據(jù)呢?我們通過下面的例子來說明。
Annotation的定義仍然使用列出來的兩個(gè),因?yàn)槲覀冃枰讷@得類文件中的注釋信息,所以必須在注釋定義中添加Retention注釋。
首先我們定義兩個(gè)注釋,注釋Todo說明了還有什么事情需要做:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Todo {
String value();
}
|
注釋Author說明了一個(gè)方法或者類的定義者:
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
@Retention(RetentionPolicy.RUNTIME)
public @interface Author {
public enum Gender{MALE,FEMALE};
String name();
String email();
Gender gender() default Gender.MALE;
}
|
然后我們在一個(gè)簡單的類中添加這兩種類型的注釋:
public @Todo("delete this class") class Foo {
public void methodA(){}
public @Author(name="B",email="b@Foo.com") void methodB(){
}
public @Author(name="A",email="a@Foo.com") String fieldA;
}
|
通過下面一段代碼我們可以提取相應(yīng)的元數(shù)據(jù):
import java.lang.reflect.Method;
public class GetAnnotations {
public static void main(String[] args) {
try {
Class<?> klass=Class.forName(args[0]);
if(klass.isAnnotationPresent(Todo.class))
{
Todo t=klass.getAnnotation(Todo.class);
System.out.println(t);
}
for(Method m:klass.getMethods())
{
if(m.isAnnotationPresent(Author.class))
{
Author a=m.getAnnotation(Author.class);
System.out.printf("Method:%s,Author:%s%n",m.getName(),a);
}
}
} catch (ClassNotFoundException e) {
e.printStackTrace();
}
}
}
|
使用下面的命令行運(yùn)行程序:
運(yùn)行結(jié)果如下:
@Todo(value=delete this class)
Method:methodB,Author:@Author(gender=MALE, name=B, email=b@Foo.com)
|
轉(zhuǎn)自:http://m.tkk7.com/jayliu/archive/2005/05/12/4209.html