Java 注解學習

  • 注解是什么

我們在平時的工作中,可能會看到形如一下的代碼:

@Entity(tableName = "user")
public class User{
  
    @Id
    @Column(name="id")
    private long id;
  
    @Column(name="uid")
    private String uid;

    ...
}

這種標記在類上,方法上,@開頭的就叫做注解.

  • 注解的用處

上圖是我們公司ORM框架的一個entity類,總所周知,ORM框架與數據庫打交道,最后也要轉為SQL語句.比如保存一條記錄,數據庫只接受INSERT INTO USER('id','uid') VALUES('1', 'huangzp')這樣的保存方式,如果當我們操作 orm.save(user),這樣的代碼的時候,實際上也是將它轉成SQL,那么對象要怎么轉成SQL呢?可以看到,要轉成SQL,至少要知道表名,字段,那么我們在類中標明類名和表名及成員變量和字段的對應關系不就OK了嗎?當我們要保存保存數據的時候,通過反射取得這些注解,然后拼成SQL.完美! 所以注解相當于一個標記,我們最后還是得通過反射等手段獲取這些注解,然后寫成我們需要的功能.

  • 定義一個注解

我們使用一個類的時候,我們要先去定義一個類,比如
public class Cat{}
同樣的,我們要使用一個注解,同樣也要去定義

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Entity {
    //注解元素
    String tableName() default "";
    //快捷方式,我們設置了value的元素的時候,設置value的值的時候,只需要@Entity("haha")而不需要@Entity(value="haha")
    String value() default "";
}
  1. @interface 是聲明一個注解,就像我們class,enum一樣.
  2. @Target 是注解修飾范圍的范圍,我們可以看一下ElementType這個枚舉類
public enum ElementType {
    /**注解在類名,接口名,枚舉名上 */
    TYPE,

    /** 注解在成員變量上 */
    FIELD,

    /** 注解在方法名上 */
    METHOD,

    /** 注解在方法參數上 */
    PARAMETER,

    /** 注解在構造方法上 */
    CONSTRUCTOR,

    /** 注解在局部變量 */
    LOCAL_VARIABLE,

    /** 注解在注解上 */
    ANNOTATION_TYPE,

    /** 注解在包名上 */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}
  1. @Retention 注解的運行時期
    A. SOURCE : 注解將被編譯器丟棄(該類型的注解信息只會保留在源碼里,源碼經過編譯后,注解信息會被丟棄,不會保留在編譯好的class文件里)
    B. CLASS : 注解在class文件中可用,但會被VM丟棄(該類型的注解信息會保留在源碼里和class文件里,在執行的時候,不會加載到虛擬機中),請注意,當注解未定義Retention值時,默認值是CLASS,如Java內置注解,@Override、@Deprecated、@SuppressWarnning等
    C. RUNTIME : 注解信息將在運行期(JVM)也保留,因此可以通過反射信機制讀取注解的息(源碼、class文件和執行的時候都有注解的信息),如SpringMvc中的@Controller、@Autowired、@RequestMapping等。
  2. 注解的元素及其類型
    String name() default "";
    在注解名花括號里的便是注解的元素,它對應的是我們寫在@Entity(name="user"),的大括號里面的東西,除了常見的string和int類型,它還可以是以下的幾種類型:
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Reference{
    boolean next() default false;
}

public @interface AnnotationElementDemo {
    //枚舉類型
    enum Status {FIXED,NORMAL};

    //聲明枚舉
    Status status() default Status.FIXED;

    //布爾類型
    boolean showSupport() default false;

    //String類型
    String name()default "";

    //class類型
    Class<?> testCase() default Void.class;

    //注解嵌套
    Reference reference() default @Reference(next=true);

    //數組類型
    long[] value();
}
  • 元注解(@Target(ElementType.ANNOTATION_TYPE))

剛剛介紹的@Target,@Retention便是元注解,元注解負責注解其他注解,Java還有@Documented 和 @Inherited 兩個元注解.

  1. @Documented 被修飾的注解會生成到javadoc中
  2. @Inherited 被注解的注解 注解的類,可以被其他類繼承,然后注解的特性會轉移到子類上,子類Class對象使用getAnnotations()獲取父類被@Inherited修飾的注解
  • Java內置注解(@Retention(RetentionPolicy.RUNTIME))

  1. @Override:用于標明此方法覆蓋了父類的方法
  2. @Deprecated:用于標明已經過時的方法或類
  3. @SuppressWarnnings:用于有選擇的關閉編譯器對類、方法、成員變量、變量初始化的警告 比如 :
    @SuppressWarnings({"uncheck","deprecation"})
  • 注解與反射

  1. public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {}
    注解通過反射獲取。首先可以通過 對象的getClass()的 isAnnotationPresent() 方法判斷它是否應用了某個注解
        User user = new User(); //開文那個類
        System.out.println(user.getClass().isAnnotationPresent(Entity.class));//運行結果: true
  1. public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {}
    然后通過 getAnnotation() 方法來獲取 Annotation 對象。
        User user = new User();
        System.out.println(user.getClass().getAnnotation(Entity.class).tableName());//運行結果為user
  1. public Annotation[] getAnnotations() {}
    或者是 getAnnotations() 方法獲取所有的Annotation對象,包括繼承的

  2. public Annotation[] getDeclaredAnnotations()
    獲取所有注解對象,不包括繼承的

最后編輯于
?著作權歸作者所有,轉載或內容合作請聯系作者
平臺聲明:文章內容(如有圖片或視頻亦包括在內)由作者上傳并發布,文章內容僅代表作者本人觀點,簡書系信息發布平臺,僅提供信息存儲服務。

推薦閱讀更多精彩內容