什么是元數據?
元數據是指用來描述數據的數據,更通俗一點,就是描述代碼間關系,或者代碼與其他資源(例如數據庫表)之間內在聯系的數據。在一些技術框架,如struts、EJB、hibernate就不知不覺用到了元數據。對struts來說,元數據指的是struts-config.xml;對EJB來說,就是ejb-jar.xml和廠商自定義的xml文件;對hibernate來說就是hbm文件。以上闡述的幾種元數據都是基於xml文件的或者其他形式的單獨配置文件。這樣表示有些不便之處。一、與被描述的文件分離,不利於一致性的維護;第二、所有這樣文件都是ASCII文件,沒有顯式的類型支持。基於元數據的廣泛應用,JDK5.0引入了Annotation的概念來描述元數據。在java中,元數據以標簽的形式存在於java代碼中,元數據標簽的存在並不影響程序代碼的編譯和執行。
如何創建元數據?
JDK5.0出來后,java語言中就有了四種類型(TYPE),即類(class)、枚舉(enum)、接口(interface)和注解(@interface),它們是處在同一級別的。java就是通過注解來表示元數據的。
一個簡單的注解定義:
public @interface MyAnnotation { // 定義公共的final靜態屬性 int age = 25; // 定義公共的抽象方法 String name(); }
反編譯字節碼文件得到:
由上我們可以得到,java的注解本質上是一個接口,而且是繼承了接口Annotation的接口。既然是接口,那么
a.注解可以有成員
注解和接口相似,它只能定義final靜態屬性和公共抽象方法。
b.注解的方法
1.方法前默認會加上public abstract且只能由這兩個修飾符修飾。屬性前默認加上public static final 且只能由這些修飾符修飾。由於是final,定義時必須初始化。
2.在聲明方法時可以定義方法的默認返回值。
例如:
String color() default "blue";
String[] color() default {"blue","red",......}
3.方法的返回值可以有哪些類型
8種基本類型,String、Class、枚舉、注解及這些類型的數組。
4.java.lang.annotation.Annotation 本身是接口,而不是注解,當使用關鍵字@interface 定義一個注解時,該注解隱含的繼承了java.lang.annotation.Annotation接口;如果我們定義一個接口,並且讓該接口繼承自Annotation,那么我們定義的接口依然是接口而不是注解。綜上,定義注解只能依靠@interface實現。
JDK提供的幾個基本注解
a. @SuppressWarnings
該注解的作用是阻止編譯器發出某些警告信息。
它可以有以下參數:
deprecation :過時的類或方法警告。
unchecked:執行了未檢查的轉換時警告。
fallthrough:當Switch程序塊直接通往下一種情況而沒有Break時的警告。
path:在類路徑、源文件路徑等中有不存在的路徑時的警告。
serial:當在可序列化的類上缺少serialVersionUID定義時的警告。
finally:任何finally子句不能完成時的警告。
all:關於以上所有情況的警告。
b.@Deprecated
該注解的作用是標記某個過時的類或方法。
c. @Override
該注解用在方法前面,用來標識該方法是重寫父類的某個方法。
元注解(注解的注解)
a. @Retention
它是被定義在一個注解類的前面,用來說明該注解的生命周期。
它有以下參數:
RetentionPolicy.SOURCE:指定注解只保留在源文件當中。
RetentionPolicy.CLASS:指定注解只保留在class文件中。(缺省)
RetentionPolicy.RUNTIME:指定注解可以保留在程序運行期間。
b. @Target
它是被定義在一個注解類的前面,用來說明該注解可以被聲明在哪些元素前。(默認可以放在任何元素之前)
它有以下參數:
ElementType.TYPE:說明該注解只能被聲明在一個類、接口、枚舉前。
ElementType.FIELD:說明該注解只能被聲明在一個類的字段前。
ElementType.METHOD:說明該注解只能被聲明在一個類的方法前。
ElementType.PARAMETER:說明該注解只能被聲明在一個方法參數前。
ElementType.CONSTRUCTOR:說明該注解只能聲明在一個類的構造方法前。
ElementType.LOCAL_VARIABLE:說明該注解只能聲明在一個局部變量前。
ElementType.ANNOTATION_TYPE:說明該注解只能聲明在一個注解類型前。
ElementType.PACKAGE:說明該注解只能聲明在一個包名前。
c. @Inherited 表明該注解將會被子類繼承。
需要說明的是,加上該元注解的注解,只有用在類元素上才有效果。這是在JDK總的原話:
Note that this meta-annotation type has no effect if the annotated
type is used to annotate anything other than a class. Note also
that this meta-annotation only causes annotations to be inherited
from superclasses; annotations on implemented interfaces have no
effect
但是在其他元素上的注解,只要你沒有覆蓋父類中的元素,是會繼承過來的。這就是為什么有getDeclaredAnnotations()和getAnnotations()的原因。
d. @Documented
表明在生成JavaDoc文檔時,該注解也會出現在javaDoc文檔中。
注解的生命周期
一個注解可以有三個生命周期,它默認的生命周期是保留在一個CLASS文件,
但它也可以由一個@Retetion的元注解指定它的生命周期。
a.java源文件
當在一個注解類前定義了一個@Retetion(RetentionPolicy.SOURCE)的注解,那么說明該注解只保留在一個源文件當中,當編譯器將源文件編譯成class文件時,它不會將源文件中定義的注解保留在class文件中。
b. class文件中
當在一個注解類前定義了一個@Retetion(RetentionPolicy.CLASS)的注解,那么說明該注解只保留在一個class文件當中,當加載class文件到內存時,虛擬機會將注解去掉,從而在程序中不能訪問。
c. 程序運行期間
當在一個注解類前定義了一個@Retetion(RetentionPolicy.RUNTIME)的注解,那么說明該注解在程序運行期間都會存在內存當中。此時,我們可以通過反射來獲得定義在某個類上的所有注解。