在現實生活中,貼標簽這種現象比比皆是。去超市,去商場,每個或者每類物品都會有它的標簽,甚至在我們自己身上也會有標簽,比如,程序猿、逗逼、單身狗、80/90后、屌絲……呵呵,太多了。有時候,我們也會戲謔朋友同事,給他們貼個標簽逗逗樂。但是這篇的正題是注解,下面我會說說為什么我理解的注解就是貼標簽,雖然有時候也會稱它為“扣帽子”。
元注解
在java提供了四個元注解,元注解就是注解的注解。它們是:
1.@Target, 2.@Retention, 3.@Documented, 4.@Inherited
在我們剛出生的時候,就已經被貼上標簽了,我們的戶籍按照地域划分,會被貼上河南河北、山東山西、湖南湖北等等23個省和四個直轄市中的其中一個。另外在我們的生命過程中也會經歷標簽的變換,小孩、未成年人、成年人、丈夫、妻子、父親、母親、爺爺奶奶等等。國家還會給我們貼上一個最普通的標簽“公民”以及我們的繼承的身份,農民或者城里人。為什么要說這些呢,因為JAVA中提供的四個元注解要表達的東西和提到的有共通之處。
@Target
@Target說明了注解修飾的范圍,就好像我們有地域划分,而Java中也會有包、接口、類、枚舉、屬性、方法、構造函數等。那么為了表示不同的區別,注解是這么寫的:
1、包 @Target(ElementType.PACKAGE)
2、接口、類、枚舉、注解 @Target(ElementType.TYPE)
3、注解 @Target(ElementType.ANNOTATION_TYPE)
4、構造函數 @Target(ElementType.CONSTRUCTOR)
5、局部變量 @Target(ElementType.LOCAL_VARIABLE)
6、方法 @Target(ElementType.METHOD)
7、方法的參數 @Target(ElementType.PARAMETER)
@Retention
@Retention表示了注解的生命周期。我們在生命過程中會隨着時間的變化而引起標簽的變化,那么我們的標簽本身也就說明了它有一定的生命周期,當我們未滿18周歲的時候叫未成年人,在我們滿18周歲的時候叫做成年人,等頭發白了,走不動就被叫做老年人,而有的標簽會伴隨一生,例如男人或者女人。在JAVA中,注解也有它的生命周期,從源代碼到編譯后的Class文件,再到被JDK加載后的運行時就是整個周期。@Retention指定了它所要注解的注解的生命周期是什么,它會存在多長時間。JAVA中我們最常見的兩個注解@SuppressWarnings和@Override,他們就只會存在於源代碼中。下面是@Retention的取值:
1、在源代碼中保留 @Retention( RetentionPolicy.SOURCE)
2、在Class文件中保留 @Retention( RetentionPolicy.CLASS)
3、在運行時保留 @Retention( RetentionPolicy.RUNTIME)
@SuppressWarnings注解的源代碼如下:
package java.lang; import java.lang.annotation.*; import java.lang.annotation.ElementType; import static java.lang.annotation.ElementType.*; @Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE}) @Retention(RetentionPolicy.SOURCE) public @interface SuppressWarnings { String[] value(); }
@Documented
默認情況下javadoc是不包括注解信息的,但是當某一個注解被貼上@Documented標簽的時候,那么當某個類或者方法的使用了被貼上@Documented這個標簽的注解的時候,javadoc就會把注解信息也包含在生成的文檔中。這個注解就不過度解讀了,如果有興趣的可以從網上自行查找相關資料。
@Inherited
@Inherited注解主要說明了一種繼承性,意思是子類可以繼承父類中的該注解(注意:只有當被貼上@Inherited標簽的注解被用在類上的時候子類才能獲得這個注解)。就像之前提到的,如果父母是農村戶口,那么他們的孩子也默認就是農村戶口了。Spring中的@Qualifier注解,代碼如下:
package org.springframework.beans.factory.annotation; import java.lang.annotation.Documented; import java.lang.annotation.ElementType; import java.lang.annotation.Inherited; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; ElementType.FIELD, ElementType.METHOD, ElementType.PARAMETER, ElementType.TYPE, ElementType.ANNOTATION_TYPE}) @Retention(RetentionPolicy.RUNTIME) @Inherited @Documented public @interface Qualifier { String value() default ""; }
@Qualifier注解可以被用在字段、方法、方法參數、類、接口、注解、枚舉上,但是只有@Qualifier被用在類上的時候才能被它的子類繼承,子類才可以獲取到這個注解。
自定義注解
除了一些我們生來就被貼上的標簽意外,我們在日常生活中不管是主動的還是被動都會去主動的給別人貼一些標簽以及被別人貼一些標簽。當我們在公司,按照職能划分,會被貼上不同的崗位標簽,便於安排工作;遲到,早退,全勤這些標簽用於考勤;優秀員工,技術達人,管理精英等標簽用來樹立標桿,有助於提高積極性和向心力。那么這些標簽被創造出來有沒有用處呢,對於公司來說自然是有用處的。但是呢,逗逼這個標簽對公司來說有沒有用處呢,我想,除非公司願意因為員工逗逼頒發逗逼獎這才有點用處,否則的話誰關心呢!貼個標簽大多數時候並不會影響正常的生活,除了個人或者組織關注了你身上的標簽的時候才會有影響,就像現在很多人一看到河南人三個字就開罵了一樣……。其實這也是為了說明,注解並不會影響程序的正常運行,有或者沒有並不影響什么,只有關注了這些注解的程序獲得並且解析了注解進行處理以后才會更改程序本身的行為。
我們知道JAVA的JDK中很多地方都用了注解,到我們使用Spring的時候,注解就被使用的更廣泛了,Spring用注解來對bean進行分類,注冊,注入以及管理,這些事情是Spring在掃描Bean的時候通過反射來獲取Bean的注解信息,配合完成Bean的自動裝配,進而進行管理,給我們提供了豐富多彩的功能。下面寫一個利用反射來處理自定義注解的例子,這個例子就是簡單生成一個建表語句,代碼如下:
1、創建@Table注解
package person.lb.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 表名 * @author nobounds * */ @Target({ElementType.TYPE}) @Retention(RetentionPolicy.RUNTIME) public @interface Table { String value() default ""; }
2、創建@Column注解:
package person.lb.annotation; import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target; /** * 字段 * @author nobounds * */ @Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Column { String name() default ""; String dataType() default "varchar(20)"; String comment() default ""; }
3、創建實體類Users:
package person.lb.annotation; @Table("users") public class Users { @Column(name="ID", dataType="int") private int id; @Column(comment="用戶名") private String userName; @Column(name="pwd", comment="密碼") private String password; @Column(dataType="varchar(25)", comment="郵箱") private String email; public String getUserName() { return userName; } public void setUserName(String userName) { this.userName = userName; } public String getPassword() { return password; } public void setPassword(String password) { this.password = password; } public String getEmail() { return email; } public void setEmail(String email) { this.email = email; } }
4、創建注解處理器AnnotationHandler:
package person.lb.annotation; import java.lang.annotation.Annotation; import java.lang.reflect.Field; public class AnnotationHandler { public static void main(String[] args) { StringBuilder sql = new StringBuilder("CREATE TABLE "); try { Class clazz = Class.forName("person.lb.annotation.Users"); //獲取Users類上的Table注解 Table tableAnnotation = (Table) clazz.getAnnotation(Table.class); //獲取表名 String tableName = tableAnnotation.value().toUpperCase(); if("".equals(tableName)) { tableName = clazz.getName().toUpperCase(); } sql.append(tableName); sql.append(" ( \n"); //獲取類中的所有字段 Field[] fields = clazz.getDeclaredFields(); for(Field field : fields) { //獲取字段上的所有注解 Annotation[] fieldAnnotations = field.getAnnotations(); if(fieldAnnotations.length > 0) { //遍歷注解 for(Annotation fieldAnnotation : fieldAnnotations) { //如果是@Field注解,那么進行處理 if(fieldAnnotation instanceof Column) { //獲取字段名 String columnName = ((Column) fieldAnnotation).name().toUpperCase(); if("".equals(columnName)) { columnName = field.getName().toUpperCase(); } //獲取數據類型 String dataType = ((Column) fieldAnnotation).dataType().toUpperCase(); //獲取注釋 String comment = ((Column) fieldAnnotation).comment(); if("".equals(comment)) { sql.append(columnName + "\t" + dataType + ",\n"); } else { sql.append(columnName + "\t" + dataType + " COMMENT '" + comment + "',\n"); } } } } } sql.append(" ) "); System.out.println("生成的sql語句為:\n" + sql.toString()); } catch (ClassNotFoundException e) { e.printStackTrace(); } } }
執行結果如下:
生成的sql語句為: CREATE TABLE USERS ( ID INT, USERNAME VARCHAR(20) COMMENT '用戶名', PWD VARCHAR(20) COMMENT '密碼', EMAIL VARCHAR(25) COMMENT '郵箱', )
上面是一個簡單的生成sql的例子,例子中忽略了某些非空判斷,邏輯並不嚴謹,僅作為參考使用。如果大家覺得有問題請留言!