java中註解的使用
1.說再前面
使用註解開發的好處
1.使程式碼更加乾淨易讀,易於維護修改。比如,以前使用spring的開發,都是基於xml檔案實現了統一的配置管理,但是缺點也是顯而易見的,就是隨著專案的越來越大,xml檔案會變得越來越複雜,維護成本也會越來越高。使用註解就可以提供更大的便捷性,易於維護修改。
2 可以實現程式碼的型別檢查,特別是在編譯器的角度實現一些型別檢查,比如預檢查(@Override)和抑制警告(@SuppressWarnings)等。
3 自定義註解,作為額外資訊的載體,儲存有關程式的額外資訊
2 註解的分類以及使用
Java註解是附加在程式碼中的一些元資訊,用於編譯和執行時進行解析和使用,起到說明、配置的功能。
註解不會影響程式碼的實際邏輯,僅僅起到輔助性的作用。包含在java.lang.annotation包中。註解的定義類似於介面的定義,使用@interface來定義,定義一個方法即為註解型別定義了一個元素,方法的宣告不允許有引數或throw語句,返回值型別被限定為原始資料型別、字串String、Class、enums、註解型別,或前面這些的陣列,方法可以有預設值。註解並不直接影響程式碼的語義,但是他可以被看做是程式的工具或者類庫。它會反過來對正在執行的程式語義有所影響。註解可以從原始檔、class檔案或者在執行時通過反射機制多種方式被讀取。
一般來說,註解一般分為三種型別: 元註解,標準註解,自定義註解
2.1 元註解
元註解是專職負責註解其他註解,主要是標明該註解的使用範圍,生效範圍。我們是不能改變它的,只能用它來定義我們自定義的註解。
包括 @Retention @Target @Document @Inherited四種。(java.lang.annotation中提供,為註釋型別)。
註解 | 說明 |
---|---|
@Target | 定義註解的作用目標,也就是可以定義註解具體作用在類上,方法上,還是變數上 |
@Retention | 定義註解的保留策略。RetentionPolicy.SOURCE:註解僅存在於原始碼中,在class位元組碼檔案中不包含;RetentionPolicy.CLASS:預設的保留策略,註解會在class位元組碼檔案中存在,但執行時無法獲得;RetentionPolicy.RUNTIME:註解會在class位元組碼檔案中存在,在執行時可以通過反射獲取到。 |
@Document | 說明該註解將被包含在javadoc中 |
@Inherited | 說明子類可以繼承父類中的該註解 |
Target型別主要依賴於ElementType這個型別,具體的型別如下:
Target型別 | 說明 |
---|---|
ElementType.TYPE | 介面、類、列舉、註解 |
ElementType.FIELD | 欄位、列舉的常量 |
ElementType.METHOD | 方法 |
ElementType.PARAMETER | 方法引數 |
ElementType.CONSTRUCTOR | 建構函式 |
ElementType.LOCAL_VARIABLE | 區域性變數 |
ElementType.ANNOTATION_TYPE | 註解 |
ElementType.PACKAGE | 包 |
2.2 標準註解
Java標準註解提供了三個,定義在java.lang中的註解,我認為這三個註解的作用更多的是一種註釋
-
@Override 表示當前方法覆蓋父類中的方法。
-
@Deprecated 標記一個元素為已過期,避免使用
支援的元素型別為:CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE
-
@SuppressWarnings 不輸出對應的編譯警告
一個簡單的使用demo:
@SuppressWarnings(value = {"unused", "rawtypes"}) public class Children extends Parent{ @Override public void work() { System.out.println("我是一個被重寫的方法"); } @Deprecated public void play(){ System.out.println("這個方法不推薦使用了"); } }
2.3 自定義註解實現一個sql語句的拼接
需要注意的方面:註解的定義類似於介面的定義,使用@interface來定義,定義一個方法即為註解型別定義了一個元素,方法的宣告不允許有引數或throw語句,返回值型別被限定為原始資料型別、字串String、Class、enums、註解型別,或前面這些的陣列,方法可以有預設值。
自定義註解一般可以分為三步: 定義註解,使用註解,讀取註解
定義註解
@Target(ElementType.TYPE) //註解載入類上
@Retention(RetentionPolicy.RUNTIME) // 執行時讀取註解
public @interface Table {
String value();
}
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public@interface UserFiled {
String name();
String type();
int length();
}
使用註解
// 將自定義的註解加在使用者上,實現一個表的對映
@Table(value = "user_table")
public class User {
@UserFiled(name = "user_id",type = "int",length = 8)
private int userId;
@UserFiled(name = "user_name",type = "varchar",length = 16)
private String userName;
@UserFiled(name = "password",type = "varchar",length = 16)
private String password;
public int getUserId() {
return userId;
}
public void setUserId(int userId) {
this.userId = userId;
}
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 class GetUser {
public static void main(String[] args) throws ClassNotFoundException, NoSuchFieldException {
Class userClass = Class.forName("annocation.blog.User");
// 讀取類上的註解
Table table = (Table) userClass.getAnnotation(Table.class);
System.out.println(table.value());
// 讀取屬性上註解
Field userId = userClass.getDeclaredField("userId");
UserFiled userFiledId = userId.getAnnotation(UserFiled.class);
System.out.println(userFiledId.length() + "----" + userFiledId.type() + "-----" + userFiledId.name());
Field userName = userClass.getDeclaredField("userName");
UserFiled userFiledName = userName.getAnnotation(UserFiled.class);
System.out.println(userFiledName.length()+"----"+userFiledName.type()+"----"+userFiledName.name());
Field password = userClass.getDeclaredField("password");
UserFiled userFiledPassword = password.getAnnotation(UserFiled.class);
System.out.println(userFiledPassword.name() + "-----" + userFiledPassword.type() + "-----" + userFiledPassword.length());
// 拼接一個sql語句
String name = "chenwei";
String sql ="select * from" + table.value()+"where"+userFiledName.name()+"="+name;
}
}
結果:
user_table
user_id----int-----8
user_name----varchar----16
password-----varchar-----16
自定義註解的實現過程:
1,定義註解
2,使用註解,根據自己定義的註解來達到一些目的,本例中,就是使用註解來完成資料庫表和實體類的對映關係
3 讀取註解的內容,也是比較重要的一部分,核心還是利用了反射的思想,得到使用註解的這個類,根據類中的getAnnotion的方法得到定義的註解,獲得註解上的值。
3 註解的實現的原理
註解的實現的原理很大的一部分是基於反射實現。
反射可以獲取到Class物件,進而獲取到Constructor、Field、Method等例項,點開原始碼結構發現Class、Constructor、Field、Method等均實現了AnnotatedElement
介面,AnnotatedElement
介面的方法如下
// 判斷該元素是否包含指定註解,包含則返回true
boolean isAnnotationPresent(Class<? extends Annotation> annotationClass)
// 返回該元素上對應的註解,如果沒有返回null
<T extends Annotation> T getAnnotation(Class<T> annotationClass);
// 返回該元素上的所有註解,如果沒有任何註解則返回一個空陣列
Annotation[] getAnnotations();
// 返回指定型別的註解,如果沒有返回空陣列
T[] getAnnotationsByType(Class<T> annotationClass)
// 返回指定型別的註解,如果沒有返回空陣列,只包含直接標註的註解,不包含inherited的註解
T getDeclaredAnnotation(Class<T> annotationClass)
// 返回指定型別的註解,如果沒有返回空陣列,只包含直接標註的註解,不包含inherited的註解
T[] getDeclaredAnnotationsByType
// 返回該元素上的所有註解,如果沒有任何註解則返回一個空陣列,只包含直接標註的註解,不包含inherited的註解
Annotation[] getDeclaredAnnotations();
通過一個例項再次說明一下註解的使用過程:
定義註解
@Documented
@Target({ElementType.TYPE, ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotaion {
String getValue() default "this is myAnntaion";
int order() default 0;
}
使用註解
@MyAnnotaion(getValue = "annotation on class")
public class Demo {
@MyAnnotaion(getValue = "annotation on filed")
public String name;
@MyAnnotaion(getValue = "annotation on method")
public void hello(){
}
@MyAnnotaion
public void defaultMethod(){
}
}
利用反射讀取註解中的值。
public class TestDemo {
public static void main(String[] args) throws NoSuchFieldException, NoSuchMethodException {
/**
* 獲取類上的註解
*/
Class<Demo> demoClass = Demo.class;
Annotation[] annotaion = demoClass.getAnnotations();
printAnnotation(annotaion);
/**
* 讀取成員變數上的註解
*/
Field name = demoClass.getField("name");
Annotation[] getOnFiled = name.getAnnotations();
printAnnotation(getOnFiled);
/**
* 讀取方法上的註解
*/
Method hello = demoClass.getMethod("hello", null);
MyAnnotaion onMethod = hello.getAnnotation(MyAnnotaion.class);
System.out.println(onMethod.getValue());
/**
* 獲取預設方法上的註解
*/
Method defaultMethod = demoClass.getMethod("defaultMethod", null);
MyAnnotaion onDefaultMethod = defaultMethod.getAnnotation(MyAnnotaion.class);
System.out.println(onDefaultMethod.getValue());
}
public static void printAnnotation(Annotation... annotations) {
for (Annotation annotation : annotations) {
System.out.println(annotation);
}
}
}
執行結果
@annocation.MyAnnotaion(getValue=annotation on class, order=0)
@annocation.MyAnnotaion(getValue=annotation on filed, order=0)
annotation on method
this is myAnntaion
參考資料:
http://blog.kimzing.com/java/Java註解入門到精通-學這一篇就夠了/
《java程式設計思想》