java 注解的基礎(chǔ)詳細(xì)介紹
java 注解的基礎(chǔ)詳細(xì)介紹
前言
注解是Java引入的一項(xiàng)非常受歡迎的補(bǔ)充,它提供了一種結(jié)構(gòu)化的,并且具有類型檢查能力的新途徑,從而使得程序員能夠?yàn)榇a加入元數(shù)據(jù),而不會(huì)導(dǎo)致代碼雜亂且難以閱讀。使用注解能夠幫助我們避免編寫累贅的部署描述文件,以及其他生成的文件。
注解的語法比較簡單,除了@符號(hào)的使用之外,它基本與java固有的語法一致。但由于java源碼中提供的內(nèi)置注解很少,所以大部分同學(xué)對(duì)注解都不是很了解,雖然我們都接觸過,比如java內(nèi)置的幾種注解:
@Override,表示當(dāng)前的方法定義將覆蓋超類中的方法。 @Deprecated,表示當(dāng)前方法即將廢棄,不推薦使用。 @SuppressWarnings,表示忽略編譯器的警告信息。
但這并不能讓我們體會(huì)到注解的強(qiáng)大和便利,其實(shí)Java還另外提供了四種注解,專門負(fù)責(zé)新注解的創(chuàng)建。今天我們就來學(xué)習(xí)下怎么創(chuàng)建和使用注解。
注解類的定義
首先看看一個(gè)注解類的定義:
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface Constraints { boolean primaryKey() default false; boolean allowNull() default true; boolean unique() default false; }
除了@符號(hào)以外,注解類的定義很像一個(gè)空的接口。定義注解時(shí),會(huì)需要一些元注解,如@Target和@Retention,java提供了四種元注解,定義如下:
@Target:表示該注解可以用于什么地方。
取值(ElementType)包括:
CONSTRUCTOR:用于描述構(gòu)造器
FIELD:用于描述域
LOCAL_VARIABLE:用于描述局部變量
METHOD:用于描述方法
PACKAGE:用于描述包
PARAMETER:用于描述參數(shù)
TYPE:用于描述類、接口(包括注解類型) 或enum聲明
@Retention:表示需要在什么級(jí)別保存該注解信息。
取值(RetentionPolicy)包括:
SOURCE:在源文件中有效(即源文件保留)
CLASS:在class文件中有效(即class保留)
RUNTIME:在運(yùn)行時(shí)有效(即運(yùn)行時(shí)保留),因此可以通過反射機(jī)制讀取注解的信息。
@Documented:表示將此注解包含在javadoc中。
@Inherited:表示允許子類繼承父類中的注解。
可以看出 定義注解格式為:
public @interface 注解名 {定義體}
注解類中定義的元素稱為注解元素,注解元素可用的類型如下:
所有基本數(shù)據(jù)類型(int,float,boolean,byte,double,char,long,short) String類型 Class類型 enum類型 Annotation類型 以上所有類型的數(shù)組
如果你使用了其它類型,那編譯器就會(huì)報(bào)錯(cuò)。注意,也不允許使用任何包裝類型,但由于自動(dòng)打包的存在,這算不上什么限制。注解也可以作為元素的類型,比如我們?cè)俣x一個(gè)注解類:
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface SQLString { int value() default 0; String name() default ""; Constraints constraints() default @Constraints; //@Constraints后沒有括號(hào)表明使用默認(rèn)值,可以加括號(hào),在里面定義初始值,比如@Constraints(unique=true) }
可以看出,所有的注解元素都有一個(gè)默認(rèn)值。編譯器對(duì)元素的默認(rèn)值有些過分挑剔,首先,元素必須具有默認(rèn)值;其次不能以null作為默認(rèn)值。所以我們只能自己定義一些特殊的值,例如空字符串或負(fù)數(shù),來表示某個(gè)元素不存在。
注解類的使用
注解類定義好了,怎么使用呢?
為了體現(xiàn)注解的便利和強(qiáng)大,在這里我們寫一個(gè)demo,使用注解來自動(dòng)生成一個(gè)建數(shù)據(jù)庫表的SQL命令。
另外我們?cè)偬峁﹥蓚€(gè)注解類:
@Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface DBTable { public String name() default ""; }
@Target(ElementType.FIELD) @Retention(RetentionPolicy.RUNTIME) public @interface SQLInteger { String name() default ""; Constraints constraints() default @Constraints; }
好,現(xiàn)在我們一共有4個(gè)注解類。
@DBTable 代表數(shù)據(jù)庫表,注解元素name表示表名;
@Constraints 代表對(duì)數(shù)據(jù)表每一列的條件補(bǔ)充,有primaryKey是不是主鍵,默認(rèn)false,allowNull是否允許為空,默認(rèn)true,unique數(shù)據(jù)是否唯一,默認(rèn)false;
@SQLString 代表表中的String列,注解元素value表示列長度,name表示列名,constraints表示對(duì)列的一些約束條件;
@SQLInteger 代表表中的int列,name表示列名,constraints表示對(duì)列的一些約束條件;
下面我們定義一個(gè)簡單的Bean類,在其中應(yīng)用以上4個(gè)注解類:
@DBTable(name = "MEMBER") public class Member { @SQLString(30) String firstName; @SQLString(50) String lastName; @SQLInteger int age; @SQLString(value = 30, constraints = @Constraints(primaryKey = true)) String handle; public String getFirstName() { return firstName; } public String getLastName() { return lastName; } public int getAge() { return age; } public String getHandle() { return handle; } public String toString() { return handle; } }
注解的元素在使用時(shí)表現(xiàn)為名-值對(duì)的形式,并需要置于 @注解類名 聲明之后的括號(hào)內(nèi)。如果沒有使用括號(hào),代表全部使用默認(rèn)值。
1、類的注解@DBTable給定了值MEMBER,它將會(huì)用來作為表的名字;
2、Bean的屬性firstName和lastName,都被注解為@SQLString類型,這些注解有兩個(gè)有趣的地方:第一,他們都使用了嵌入的@Constraints注解的默認(rèn)值;第二,它們都使用了快捷方式。何謂快捷方式?如果程序員的注解中定義了名為value的元素,并且在應(yīng)用該注解的時(shí)候,如果該元素是唯一需要賦值的一個(gè)元素,那么此時(shí)無需使用名-值對(duì)的這種語法,而只需在括號(hào)內(nèi)給出value元素所需的值即可。這可以應(yīng)用于任何合法類型的元素。當(dāng)然了,這也限制了程序員必須將此元素命名為value。
Bean屬性age全部使用默認(rèn)值,handle為主鍵。
3、Bean屬性age全部使用默認(rèn)值,handle為主鍵。
實(shí)現(xiàn)注解處理器
注解類使用上了,我們還需要一個(gè)注解處理器來解析我們定義的Bean,這樣才能將注解轉(zhuǎn)換成我們需要的操作。
以下定義解析Bean的注解處理器,我們的目的是要輸出一條SQL語句。主要用到了反射技術(shù)。
public class TableCreator { public static void main(String[] args) throws Exception{ //傳入我們定義好的Bean類名,帶上包名 Class<?> cl = Class.forName("annotation.Member"); //檢查我們傳入的類是否帶有@DBTable注解 DBTable dbTable = cl.getAnnotation(DBTable.class); List<String> columnDefs = new ArrayList<String>(); //得到類中的所有定義的屬性 for(Field filed : cl.getDeclaredFields()){ String columnName = null; //得到屬性的注解,對(duì)一個(gè)目標(biāo)可以使用多個(gè)注解 Annotation[] anns = filed.getAnnotations(); if(anns.length < 1){ continue; } //SQLString注解走著 if(anns[0] instanceof SQLString){ SQLString sString = (SQLString)anns[0]; //name()使用的是默認(rèn)值,所以這里取屬性名 if(sString.name().length() < 1){ columnName = filed.getName().toUpperCase(); }else{ columnName = sString.name(); } //構(gòu)建SQL語句 columnDefs.add(columnName + " VARCHAR(" + sString.value() + ")" + getConstraints(sString.constraints())); } //SQLInteger注解走著 if(anns[0] instanceof SQLInteger){ SQLInteger sInt = (SQLInteger)anns[0]; if(sInt.name().length() < 1){ columnName = filed.getName().toUpperCase(); }else{ columnName = sInt.name(); } columnDefs.add(columnName + " INT" + getConstraints(sInt.constraints())); } } StringBuilder creator = new StringBuilder("CREATE TABLE " + dbTable.name() + "( "); for(String c : columnDefs){ creator.append("\n" + c + ","); } creator.deleteCharAt(creator.length()-1); creator.append(")"); System.out.println(creator.toString()); } private static String getConstraints(Constraints con) { String constraints = ""; if(!con.allowNull()){ constraints += " NOT NULL"; } if(con.primaryKey()){ constraints += " PRIMARY KEY"; } if(con.unique()){ constraints += " UNIQUE"; } return constraints; } }
最后的輸出:
CREATE TABLE MEMBER( FIRSTNAME VARCHAR(30), LASTNAME VARCHAR(50), AGE INT, HANDLE VARCHAR(30) PRIMARY KEY)
總結(jié)
最后,通過這篇文章,我們要學(xué)到一下幾點(diǎn):
1、了解Java 4種元注解的說明與使用;
2、會(huì)自定義注解類;
3、了解注解元素的定義和規(guī)則;
4、會(huì)使用注解類;
5、能寫一個(gè)簡單的注解處理器解析注解。
如有疑問請(qǐng)留言或者到本站社區(qū)交流討論,感謝閱讀,希望能幫助到大家,謝謝大家對(duì)本站的支持!
相關(guān)文章
JAVA中的final關(guān)鍵字用法實(shí)例詳解
這篇文章主要介紹了JAVA中的final關(guān)鍵字用法,結(jié)合實(shí)例形式較為詳細(xì)的分析了Java中的final關(guān)鍵字用于修飾數(shù)據(jù),方法及類的具體使用技巧,需要的朋友可以參考下2015-12-12淺析java中String類型中“==”與“equal”的區(qū)別
這篇文章主要介紹了淺析java中String類型中“==”與“equal”的區(qū)別,本文給大家介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下2020-08-08使用@Valid+BindingResult進(jìn)行controller參數(shù)校驗(yàn)方式
這篇文章主要介紹了使用@Valid+BindingResult進(jìn)行controller參數(shù)校驗(yàn)方式,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。如有錯(cuò)誤或未考慮完全的地方,望不吝賜教2021-12-12MyBatis-Plus如何關(guān)閉SQL日志打印詳解
在使用mybatisplus進(jìn)行開發(fā)時(shí),日志是一個(gè)非常有用的工具,它可以幫助我們更好地了解和調(diào)試我們的代碼,這篇文章主要給大家介紹了關(guān)于MyBatis-Plus如何關(guān)閉SQL日志打印的相關(guān)資料,需要的朋友可以參考下2024-03-03