在用hibernate
的時候發現idea
能自動生成JavaBean
,同時帶有一些注解,這引起了我的好奇。當在學習Android
的時候,我發現XUtils
這個工具包中的DBUtils也能夠使用類似hibernate
的注解。於是乎在java編程思想中找了找有關注解的用法。
注解(也稱為元數據)為我們在代碼中添加信息提供了一種形式化的方法,使我們可以在稍後某個時刻非常方便的使用這些數據。注解來源於C#之類的其他語言。
注解的語法比較簡單,除了@
符號外,它與java的固有語法一致。javaSE5中內置了三種注解:
@Override:定義覆蓋超類,當覆寫對應不上被覆蓋的方法,編譯器發出錯誤提示。
@Deprecated:當使用了該注解,即表示這個方法已經不推薦被使用。
@SuppressWarnings:關閉不當的編譯器警告。
我們使用自定義的注解對一個方法進行注解:
public class Testable{
public void execute()
{
System.out.println("execute...");
}
@WETest
void taskStart()
{
execute();
}
}
在上邊的代碼中,我們對taskStart方法使用了注解,接下來我們對WETest注解進行定義:
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface WETest{}
我們給上邊的注解添加一些內容:
import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface WETest{
public int id();
public String Notes() default "there is no Notes";
}
同樣,我們對Testable類使用最新的注解:
public class Testable{
@WETest(id=666)
public void execute()
{
System.out.println("execute...");
}
@WETest(id=666,Notes="this is a method")
void taskStart()
{
execute();
}
}
注解就是這麼使用的,當注解內容沒有填寫時,他會使用默認的值,如execute方法,他沒有定義Notes,那麼Notes默認值為"there is no Notes"。
我們看到注解上邊有兩行內容,它們是元注解,專門對注解的解釋。元注解一共有四種,分別是:
@Target:表示該注解可以用到哪些地方,ElementType,CONSTRUCTOR構造器聲明,FIELD域聲明(包括enum實例),LOCAL_VARIABLE局部變量聲明,METHOD方法,PACKAGE包,PARAMETER參數,TYPE類、接口或enum。
@Retention:表示需要在什麼級別上使用,RetentionPolicy,SOURCE注解會被編譯器丟掉,CLASS在class文件中可用會被VM拋棄,RUNTIME在VM運行期也會保留可以通過反射獲取注解信息。
@Documented:將注解包含在Javadoc中。
@Inherited:允許子類繼承父類中的注解。
接下來,我用一個例子來解釋注解的作用。先編寫一些注解定義:
//DBTable.java 用來生成數據表
package annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface DBTable {
public String name() default "";
}
//Constraints.java 用來定義約束項
package annotations;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
boolean primarykey() default false;
boolean allownull() default true;
}
//PrimaryKey.java 將Constraints中的primarykey定義為真,表示為主鍵
package annotations;
import java.lang.annotation.*;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface PrimaryKey {
Constraints constraints() default @Constraints(primarykey = true);
}
//SQLInteger.java 定義列的類型
package annotations;
import java.lang.annotation.*;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {
String name() default "";
Constraints constraints() default @Constraints;
}
//SQLString.java 定義列的類型
package annotations;
import java.lang.annotation.*;
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
int value() default 64;
String name() default "";
Constraints constraints() default @Constraints;
}
接下來寫一個javabean,使用上述注解:
//User.java
import annotations.Constraints;
import annotations.DBTable;
import annotations.SQLInteger;
import annotations.SQLString;
@DBTable(name="user")
public class User {
@SQLInteger(name="id",constraints = @Constraints(primarykey=true))
public Integer id;
@SQLString(value=30)
public String name;
@SQLString(name="passwd",constraints=@Constraints(allownull=false))
public String password;
/*可以不用
public void setId(Integer id) {
this.id = id;
}
public void setName(String name) {
this.name = name;
}
public void setPassword(String password) {
this.password = password;
}
public Integer getId() {
return id;
}
public String getName() {
return name;
}
public String getPassword() {
return password;
}*/
}
我們看到注解中可以使用注解,在SQLInteger
中我們使用了Constraints注解。
接下來我們寫一個注解處理器:
//Test.java
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.util.ArrayList;
import java.util.List;
import java.util.Scanner;
import annotations.Constraints;
import annotations.DBTable;
import annotations.SQLInteger;
import annotations.SQLString;
public class Test {
public static String getConstraints(Constraints con)
{
String constraints = "";
if(!con.allownull())
{
constraints +=" NOT NULL";
}
if(con.primarykey())
{
constraints += " PRIMARY KEY";
}
return constraints;
}
public static void main(String[] args) throws ClassNotFoundException {
Scanner s = new Scanner(System.in);
String name = s.next(); //從控制台輸入一個類名,我們輸入User即可
Class<?> cl = Class.forName(name); //加載類,如果該類不在默認路徑底下,會報 java.lang.ClassNotFoundException
DBTable dbTable = cl.getAnnotation(DBTable.class); //從User類中獲取DBTable注解
if(dbTable == null){ //如果沒有DBTable注解,則直接返回,我們寫了,當然有
return;
}
String tableName = (dbTable.name().length()<1)?cl.getName():dbTable.name();//獲取表的名字,如果沒有在DBTable中定義,則獲取類名作為Table的名字
List<String> columnDefs = new ArrayList<String>();
for(Field field : cl.getDeclaredFields()) //獲取聲明的屬性
{
String columnName = null;
Annotation[] anns = field.getDeclaredAnnotations();//獲取注解,一個屬性可以有多個注解,所以是數組類型
if(anns.length < 1)
{
continue;
}
if(anns[0] instanceof SQLInteger) //判斷注解類型
{
SQLInteger sInt = (SQLInteger)anns[0];
columnName = (sInt.name().length()<1)?field.getName():sInt.name();//獲取列名稱與獲取表名一樣
columnDefs.add(columnName+" INT"+getConstraints(sInt.constraints()));//使用一個方法,自己寫的getConstraints(Constraints constraints)獲取列定義
}
if(anns[0] instanceof SQLString)
{
SQLString sStr = (SQLString)anns[0];
columnName = (sStr.name().length()<1)?field.getName().toUpperCase():sStr.name();
columnDefs.add(columnName + " VARCHAR("+sStr.value()+")"+getConstraints(sStr.constraints()));
}
}
StringBuilder createCommand = new StringBuilder("CREATE TABLE "+tableName+"(");
for(String columnDef :columnDefs)
{
createCommand.append("\n "+columnDef+",");
}
String tableCreate = createCommand.substring(0,createCommand.length()-1)+"\n);";
System.out.println(tableCreate); //打印出來
}
}
我們可以采用上述方法動態的處理一些數據,例如創建數據表。
注意:注解不支持繼承例如 extends @xxx。
注解的default默認值不可以為null
使用注解可以減少對xml等外部文件的依賴,使得對類的定義可以在一處實現,避免了一個類兩處定義的麻煩。spring和hibernate就采用的這樣的方法。
Hibernate+JUnit測試實體類生成數據庫表 http://www.linuxidc.com/Linux/2015-07/120161.htm
Hibernate整體理解 http://www.linuxidc.com/Linux/2014-07/104405.htm
Hibernate的映射機制 http://www.linuxidc.com/Linux/2014-12/110265.htm
Hibernate 的詳細介紹:請點這裡
Hibernate 的下載地址:請點這裡