反射註解筆記java
1. 註解
什麼註解?數據庫
註解:annotation(標識,標籤),從Java5開始支持註解ide
註解能幹什麼?函數
註解是貼在java程序元素上面測試
程序元素 : 類,方法,字段,方法參數,接口,構造函數,枚舉this
註解貼在程序上面有什麼用?spa
在反射的時候,動態能夠獲取字節碼,方法,字段等等程序元素,獲取了這些程序元素,那麼就能獲取程序元素上貼的註解。這些註解會參與程序運行提供比較的相關信息和數據blog
枚舉是一個特殊類繼承
註解是一個特殊的接口,全部的註解都繼承自java.lang.annotation這個接口。接口
完整的註解(從編寫到最終運行)須要三方面的參與。
1.須要定義一個註解。
2.須要一個被貼的程序元素(類,方法,字段,構造器等)
3.第三方程序的支持(賦予我註解的特殊功能)
1.1. JDK中內置的註解
1.@Override 限定覆寫父類方法 2.@Deprecated 標記已過期的成員,被標記的方法不推薦使用. 問題1:有的註解能夠貼在類上,方法上,字段上,有的卻只能貼在類上 問題2:有的註解能夠有一個或者多個參數,有的卻不行。 |
1.2. JDK中的元註解
註解: 貼在程序元素上面的標籤
元註解 : 註解的註解(貼在註解上面的註解)
元註解 主要用於限定當前的註解可以貼在哪兒?可以保留在哪一個階段(程序執行三個階段
源代碼階段,字節碼階段,JVM中)
@Retention: 表示註解能夠保存在哪個時期.
保存的時期的值,封裝在RetentionPolicy枚舉類中
枚舉常量摘要 |
CLASS |
註解保留到字節碼階段,運行時候失效了 |
RUNTIME |
註解保留到運行階段,運行時候使用反射獲取作相應的程序處理-通常開發者自定註解都保留運行階段 |
SOURCE |
註解在源代碼階段有效,編譯字節碼就失效了 |
|
@Target: 表示註解能夠貼在哪些位置(類,方法上,構造器上等等).
位置的常量封裝在ElementType枚舉類中:
ElementType.ANNOTATION_TYPE只能修飾Annotation
ElementType.CONSTRUCTOR只能修飾構造方法
ElementType.FIELD只能修飾字段(屬性),包括枚舉常量
ElementType.LOCAL_VARIABLE只能修飾局部變量
ElementType.METHOD只能修飾方法
ElementType.PACKAGE只能修飾包(極少使用)
ElementType.PARAMETER只能修飾參數
ElementType.TYPE只能修飾類,接口,枚舉
1.3. 自定義註解
- 定義一個註解
語法 : 註解關鍵字 @Interface
- 被貼的程序元素
- 第三方程序參與賦予註解功能(反射程序)
程序代碼
package cn.zj.annotation;
import java.lang.annotation.ElementType; import java.lang.annotation.Retention; import java.lang.annotation.RetentionPolicy; import java.lang.annotation.Target;
/** * 設置註解的元註解 * 1,Target * 註解能夠貼在那些程序元素上面 * 2, Retention * 註解能夠保留到那個階段,通常自定義保留到RUNTIME運行時 * */ @Target(ElementType.TYPE) @Retention(RetentionPolicy.RUNTIME) public @interface Table { /** * 註解屬性 * 語法 * 數據類型 屬性名稱(); * 若是屬性名稱是 value ,在使用註解的時候,能夠省略 value */
//String value(); String name();
} |
package cn.zj.annotation;
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 Column {
String value(); } |
package cn.zj.pojo;
import cn.zj.annotation.Column;
import cn.zj.annotation.Table;
/** * @Table 註解的做用就是爲了解決在反射時候,實體類和 代表不匹配 * 實體類 :User --> user 理論上對應數據表 user * 實際上數據庫表名 :t_user * 這樣若是默認不匹配 反射時候對不上,反射封裝存儲數據就失敗 */
@Table(name="t_user") public class User { private Integer id;
@Column("username") private String name; private String password; private String email; private String phone;
public Integer getId() { return id; }
public String getName() { return name; }
public String getPassword() { return password; }
public String getEmail() { return email; }
public String getPhone() { return phone; }
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 void setEmail(String email) { this.email = email; }
public void setPhone(String phone) { this.phone = phone; }
@Override public String toString() { return "User{" + "id=" + id + ", name='" + name + '\'' + ", password='" + password + '\'' + ", email='" + email + '\'' + ", phone='" + phone + '\'' + '}'; } } |
測試代碼
package cn.zj.test;
import cn.zj.annotation.Column; import cn.zj.annotation.Table; import cn.zj.pojo.User;
import java.lang.reflect.Field;
public class AnnotationTest {
//使用反射獲取字節碼,並獲取對應元素的註解 public static void main(String[] args) {
//1.獲取User類的字節碼實例 Class<User> clz = User.class;
//2.判斷類上面是否有 @Table註解
boolean flag = clz.isAnnotationPresent(Table.class); if(flag){ //1.獲取@Table註解 Table table = clz.getAnnotation(Table.class);
System.out.println(table);
//2.獲取具體的屬性值 String tableName = table.name();
System.out.println(tableName);
}
//2.獲取全部字段
Field[] fields = clz.getDeclaredFields();
for (Field field : fields) { //1.判斷字段上是否有註解
if(field.isAnnotationPresent(Column.class)){
//2.獲取字段上的註解 Column column = field.getAnnotation(Column.class); System.out.println(column); } } }} |