小男孩‘自慰网亚洲一区二区,亚洲一级在线播放毛片,亚洲中文字幕av每天更新,黄aⅴ永久免费无码,91成人午夜在线精品,色网站免费在线观看,亚洲欧洲wwwww在线观看

分享

秒懂 Java注解類型(@Annotation)

 quasiceo 2018-08-12

秒懂 Java注解類型(@Annotation)

2018年06月08日 18:18:50
閱讀數(shù):119

版權(quán)申明】非商業(yè)目的可自由轉(zhuǎn)載
博文地址:https://blog.csdn.net/shusheng0007/article/details/80622035
出自:shusheng007

概述

照例先啰嗦幾句,剛開始接觸Java的時候,某一天發(fā)現(xiàn)調(diào)用的一個方法被劃了一個刪除橫線,查看這個方法的源代碼的時候發(fā)現(xiàn)除了上面有一句@Deprecated代碼外,和其他方法沒有區(qū)別,所以我斷定就是這貨起的作用,當(dāng)時覺得好神奇,于是乎我開始了對Java注解的了解,這個過程是不連續(xù)的,最近比較閑,所以總結(jié)一下。

理解Java注解

注解就相當(dāng)于對源代碼打的標(biāo)簽,給代碼打上標(biāo)簽和刪除標(biāo)簽對源代碼沒有任何影響。有的人要說了,你盡幾把瞎扯,沒有影響,打這些標(biāo)簽干毛線呢?其實不是這些標(biāo)簽自己起了什么作用,而且外部工具通過訪問這些標(biāo)簽,然后根據(jù)不同的標(biāo)簽做出了相應(yīng)的處理。這是注解的精髓,理解了這一點一切就變得不再那么神秘。
例如我們寫代碼用的IDE(例如 IntelliJ Idea),它檢查發(fā)現(xiàn)某一個方法上面有@Deprecated這個注解,它就會在所有調(diào)用這個方法的地方將這個方法標(biāo)記為刪除。

訪問和處理Annotation的工具統(tǒng)稱為APT(Annotation Processing Tool)

基本語法

注解可以分為以下3類

基本注解

Java內(nèi)置的注解共有5個

@Override:讓編譯器檢查被標(biāo)記的方法,保證其重寫了父類的某一個方法。此注解只能標(biāo)記方法。源碼如下:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
  • 1
  • 2
  • 3
  • 4

@Deprecated:標(biāo)記某些程序元素已經(jīng)過時,程序員請不要再使用了。源碼如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}
  • 1
  • 2
  • 3
  • 4
  • 5

@SuppressWarnings :告訴編譯器不要給老子顯示警告,老子不想看,老子清楚的知道自己在干什么。源碼如下:

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}           
  • 1
  • 2
  • 3
  • 4
  • 5

其內(nèi)部有一個String數(shù)組,根據(jù)傳入的值來取消相應(yīng)的警告:
deprecation:使用了不贊成使用的類或方法時的警告;
unchecked:執(zhí)行了未檢查的轉(zhuǎn)換時的警告,例如當(dāng)使用集合時沒有用泛型 (Generics) 來指定集合保存的類型;
fallthrough:當(dāng) Switch 程序塊直接通往下一種情況而沒有 Break 時的警告;
path:在類路徑、源文件路徑等中有不存在的路徑時的警告;
serial:當(dāng)在可序列化的類上缺少 serialVersionUID 定義時的警告;
finally:任何 finally 子句不能正常完成時的警告;
all:關(guān)于以上所有情況的警告。

@SafeVarargs(Java7 新增)@SuppressWarnings可以用在各種需要取消警告的地方,而 @SafeVarargs主要用在取消參數(shù)的警告。就是說編譯器如果檢查到你對方法參數(shù)的操作,有可能發(fā)生問題時會給出警告,但是你很自(任)性,老子不要警告,于是你就加上了這個標(biāo)簽。源碼如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.CONSTRUCTOR, ElementType.METHOD})
public @interface SafeVarargs {}
  • 1
  • 2
  • 3
  • 4

其實這個注解是專為取消堆污染警告設(shè)置的,因為Java7會對可能產(chǎn)生堆污染的代碼提出警告,什么是堆污染?且看下面代碼

 @SafeVarargs
 private static void method(List<String>... strLists) {
     List[] array = strLists;
     List<Integer> tmpList = Arrays.asList(42);
     array[0] = tmpList; //非法操作,但是沒有警告
     String s = strLists[0].get(0); //ClassCastException at runtime!
 }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如果不使用 @SafeVarargs,這個方法在編譯時候是會產(chǎn)生警告的 : “…使用了未經(jīng)檢查或不安全的操作?!?/strong>,用了就不會有警告,但是在運(yùn)行時會拋異常。

@FunctionalInterface(Java8 新增): 標(biāo)記型注解,告訴編譯器檢查被標(biāo)注的接口是否是一個函數(shù)接口,即檢查這個接口是否只包含一個抽象方法,只有函數(shù)接口才可以使用Lambda表達(dá)式創(chuàng)建實例。源碼如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface FunctionalInterface {}
  • 1
  • 2
  • 3
  • 4

元注解

用來給其他注解打標(biāo)簽的注解,即用來注解其他注解的注解。元注解共有6個。從上面的基本注解的源代碼中就會看到使用了元注解來注解自己。

@Retention:用于指定被此元注解標(biāo)注的注解的保留時長,源代碼如下:

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Retention {
        RetentionPolicy value();
    }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

從源代碼中可以看出,其有一個屬性value,返回一個枚舉RetentionPolicy 類型,有3種類型:

  • RetentionPolicy.SOURCE: :注解信息只保留在源代碼中,編譯器編譯源碼時會將其直接丟棄。
  • RetentionPolicy.CLASS::注解信息保留在class文件中,但是虛擬機(jī)VM不會維護(hù)默認(rèn)值。
  • RetentionPolicy.RUNTIME::注解信息保留在class文件中,而且VM也會持有此注解信息,所以可以通過反射的方式獲得注解信息。

@Target:用于指定被此元注解標(biāo)注的注解可以標(biāo)注的程序元素,源碼如下:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6

從源碼中可以看出,其有一個屬性value,返回一個枚舉ElementType類型的數(shù)組,這個數(shù)組的值就代表了可以使用的程序元素。

public enum ElementType {
   /**標(biāo)明該注解可以用于類、接口(包括注解類型)或enum聲明*/
   TYPE,

   /** 標(biāo)明該注解可以用于字段(域)聲明,包括enum實例 */
   FIELD,

   /** 標(biāo)明該注解可以用于方法聲明 */
   METHOD,

   /** 標(biāo)明該注解可以用于參數(shù)聲明 */
   PARAMETER,

   /** 標(biāo)明注解可以用于構(gòu)造函數(shù)聲明 */
   CONSTRUCTOR,

   /** 標(biāo)明注解可以用于局部變量聲明 */
   LOCAL_VARIABLE,

   /** 標(biāo)明注解可以用于注解聲明(應(yīng)用于另一個注解上)*/
   ANNOTATION_TYPE,

   /** 標(biāo)明注解可以用于包聲明 */
   PACKAGE,

   /**
    * 標(biāo)明注解可以用于類型參數(shù)聲明(1.8新加入)
    */
   TYPE_PARAMETER,

   /**
    * 類型使用聲明(1.8新加入)
    */
   TYPE_USE
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35

例如@Override注解使用了 @Target(ElementType.METHOD),那么就意味著,它只能注解方法,不能注解其他程序元素。

當(dāng)注解未指定Target值時,則此注解可以用于任何元素之上,多個值使用{}包含并用逗號隔開,下面代碼表示,此Annotation既可以注解構(gòu)造函數(shù)、字段和方法:

@Target(value={CONSTRUCTOR, FIELD, METHOD})
  • 1

值得注意的是TYPE_PARAMETER,TYPE_USE是Java8 加入的新類型,在Java8之前,只能在聲明各種程序元素時使用注解,而TYPE_PARAMETER允許使用注解修飾參數(shù)類型,TYPE_USE允許使用注解修飾任意類型。

//TYPE_PARAMETER 修飾類型參數(shù)
class A<@Parameter T> { }

//TYPE_USE則可以用于標(biāo)注任意類型(不包括class)

//用于父類或者接口
class Image implements @Rectangular Shape { }

//用于構(gòu)造函數(shù)
new @Path String("/usr/bin")

//用于強(qiáng)制轉(zhuǎn)換和instanceof檢查,注意這些注解中用于外部工具,它們不會對類型轉(zhuǎn)換或者instanceof的檢查行為帶來任何影響。
String path=(@Path String)input;
if(input instanceof @Path String)

//用于指定異常
public Person read() throws @Localized IOException.

//用于通配符綁定
List<@ReadOnly ? extends Person>
List<? extends @ReadOnly Person>

@NotNull String.class //非法,不能標(biāo)注class
import java.lang.@NotNull String //非法,不能標(biāo)注import
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24

雖然Java8 提供了類型注解,但是沒有提供APT,所以需要框架自己實現(xiàn)。

@Documented:將被標(biāo)注的注解生成到javadoc中。

@Inherited:其讓被修飾的注解擁有被繼承的能力。如下,我們有一個用@Inherited修飾的注解@InAnnotation,那么這個注解就擁有了被繼承的能力。

@Inherited
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface InAnnotation{
}

@InAnnotation
class Base{}

class Son extends Base{}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10

當(dāng)使用此注解修飾一個基類Base, 其子類Son 并沒有使用任何注解修飾,但是其已經(jīng)擁有了@InAnnotation這個注解,相當(dāng)于Son 已經(jīng)被@InAnnotation修飾了

@Repeatable :使被修飾的注解可以重復(fù)的注解某一個程序元素。例如下面的代碼中@ShuSheng這個自定義注解使用了@Repeatable修飾,所以其可以按照下面的語法重復(fù)的注解一個類。

@ShuSheng(name="frank",age=18)
@ShuSheng(age = 20)
public class AnnotationDemo{}
  • 1
  • 2
  • 3

如何定義一個重復(fù)注解呢,如下所示,我們需要先定義一個容器,例如ShuShengs ,然后將其作為參數(shù)傳入@Repeatable中。

@Repeatable(ShuShengs.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ShuSheng {
    String name() default "ben";
    int age();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ShuShengs {
    ShuSheng[] value();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13

自定義注解

通過前面的講解,很容易得出如何自定義一個注解。注解是以關(guān)鍵字@interface 來定義的,下面我們自定義一個注解。
注解按照有無成員變量可以分為:

  • 標(biāo)記Annotation:無成員變量,只利用自身是否存在來提供信息。

    @Target(ElementType.METHOD)//只能應(yīng)用于方法上。
    @Retention(RetentionPolicy.RUNTIME)//保存到運(yùn)行時
    public @interface Test {
    }
    • 1
    • 2
    • 3
    • 4
  • 元數(shù)據(jù)Annotation:有一個或者多個成員變量,可以接收外界信息。

    @Target(ElementType.TYPE)//只能應(yīng)用于類型上,包括類,接口。
    @Retention(RetentionPolicy.RUNTIME)//保存到運(yùn)行時
    public @interface Table {
        String name() default "";
    }
    • 1
    • 2
    • 3
    • 4
    • 5

    以上就是我們定義的兩種注解,那么如何使用呢

//在類上使用該注解
@Table (name = "MEMBER")
public class Member {
    @Test 
    public void method()
    {...}
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

如何使用注解

就像我們文章開頭說的,當(dāng)我們使用注解修飾了程序元素后,這種Annotation不會自己起作用,的需要APT的幫助,那么這些APT就需要讀取代碼中的屬性信息,那么如何讀取呢?答案是通過反射

Annotation接口是所有注解的父接口(需要通過反編譯查看),在java.lang.reflect 反射包下存在一個叫AnnotatedElement接口,其表示程序中可以接受注解的程序元素,例如 類,方法,字段,構(gòu)造函數(shù),包等等。而Java為使用反射的主要類實現(xiàn)了此接口,如反射包內(nèi)的Constructor類、Field類、Method類、Package類和Class類。

當(dāng)我們通過反射技術(shù)獲取到反射包內(nèi)的那些類型的實例后,就可以使用AnnotatedElement接口的中的API方法來獲取注解的信息了。

  • <T extends Annotation> T getAnnotation(Class<T> annotationClass); : 返回該元素上存在的指定類型的注解,如果不存在則返回 null。
  • default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass){} :返回該元素上存在的直接修飾該元素的指定類型的注解,如果不存在則返回null.
  • Annotation[] getAnnotations();:返回該元素上存在的所有注解。
  • Annotation[] getDeclaredAnnotations();:返回該元素上存在的直接修飾該元素的所有注解。
  • default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass){}:該方法功能與前面getAnnotation方法類似,但是由于Java8 加入了重復(fù)注解功能,因此需要此方法獲取修飾該程序元素的指定類型的多個Annotation

獲取注解簡單示例

首先我們定義了兩個注解@Master@ShuSheng,@ShuSheng是一個可重復(fù)注解

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Master {
}


@Repeatable(ShuShengs.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ShuSheng {
    String name() default "ben";
    int age();
}

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface ShuShengs {
    ShuSheng[] value();
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19

然后我們定義了兩個類,使用定義好的注解來修飾,如下

@Master
public class AnoBase {
}

@ShuSheng(name="frank",age=18)
@ShuSheng(age = 20)
public class AnnotationDemo extends AnoBase{
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9

最后我們來調(diào)用相關(guān)函數(shù)獲取相應(yīng)的結(jié)果
private static void getAnnotation()

   {
       Class<?> cInstance=AnnotationDemo.class;

       //獲取AnnotationDemo上的重復(fù)注解
       ShuSheng[] ssAons= cInstance.getAnnotationsByType(ShuSheng.class);
       System.out.println("重復(fù)注解:"+Arrays.asList(ssAons).toString());

       //獲取AnnotationDemo上的所有注解,包括從父類繼承的
       Annotation[] allAno=cInstance.getAnnotations();
       System.out.println("所有注解:"+Arrays.asList(allAno).toString());

       //判斷AnnotationDemo上是否存在Master注解
       boolean isP=cInstance.isAnnotationPresent(Master.class);
       System.out.println("是否存在Master: "+isP);
   }
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15

執(zhí)行結(jié)果如下:

重復(fù)注解:[@top.ss007.ShuSheng(name=frank, age=18), @top.ss007.ShuSheng(name=ben, age=20)]
所有注解:[@top.ss007.ShuShengs(value=[@top.ss007.ShuSheng(name=frank, age=18), @top.ss007.ShuSheng(name=ben, age=20)])]
是否存在Master: false
  • 1
  • 2
  • 3

自定義注解處理器(APT)

了解完注解與反射的相關(guān)API后,就可以更進(jìn)一步。下面的實例自定義了一個APT,完成通過注解構(gòu)建SQL語句的功能。此處代碼來自此處。下面代碼要求對數(shù)據(jù)庫有初步認(rèn)識。

先定義相關(guān)的注解

/**
 * 用來注解表
 */
@Target(ElementType.TYPE)//只能應(yīng)用于類上
@Retention(RetentionPolicy.RUNTIME)//保存到運(yùn)行時
public @interface DBTable {
    String name() default "";
}

/**
 * 注解Integer類型的字段
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLInteger {
    //該字段對應(yīng)數(shù)據(jù)庫表列名
    String name() default "";
    //嵌套注解
    Constraints constraint() default @Constraints;
}

/**
 * 注解String類型的字段
 */
@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
public @interface SQLString {
    //對應(yīng)數(shù)據(jù)庫表的列名
    String name() default "";
    //列類型分配的長度,如varchar(30)的30
    int value() default 0;
    Constraints constraint() default @Constraints;
}

/**
 * 約束注解
 */
@Target(ElementType.FIELD)//只能應(yīng)用在字段上
@Retention(RetentionPolicy.RUNTIME)
public @interface Constraints {
    //判斷是否作為主鍵約束
    boolean primaryKey() default false;
    //判斷是否允許為null
    boolean allowNull() default false;
    //判斷是否唯一
    boolean unique() default false;
}

/**
 * 數(shù)據(jù)庫表Member對應(yīng)實例類bean
 */
@DBTable(name = "MEMBER")
public class Member {
    //主鍵ID
    @SQLString(name = "ID",value = 50, constraint = @Constraints(primaryKey = true))
    private String id;

    @SQLString(name = "NAME" , value = 30)
    private String name;

    @SQLInteger(name = "AGE")
    private int age;

    @SQLString(name = "DESCRIPTION" ,value = 150 , constraint = @Constraints(allowNull = true))
    private String description;//個人描述

   //省略set get.....
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68

上述定義4個注解,分別是@DBTable(用于類上)、@Constraints(用于字段上)、 @SQLString(用于字段上)、@SQLString(用于字段上)并在Member類中使用這些注解,這些注解的作用的是用于幫助注解處理器生成創(chuàng)建數(shù)據(jù)庫表MEMBER的構(gòu)建語句,在這里有點需要注意的是,我們使用了嵌套注解@Constraints,該注解主要用于判斷字段是否為null或者字段是否唯一。接下來就需要編寫我們自己的注解處理器了。

public class TableCreator {

  public static String createTableSql(String className) throws ClassNotFoundException {
    Class<?> cl = Class.forName(className);
    DBTable dbTable = cl.getAnnotation(DBTable.class);
    //如果沒有表注解,直接返回
    if(dbTable == null) {
      System.out.println(
              "No DBTable annotations in class " + className);
      return null;
    }
    String tableName = dbTable.name();
    // If the name is empty, use the Class name:
    if(tableName.length() < 1)
      tableName = cl.getName().toUpperCase();
    List<String> columnDefs = new ArrayList<String>();
    //通過Class類API獲取到所有成員字段
    for(Field field : cl.getDeclaredFields()) {
      String columnName = null;
      //獲取字段上的注解
      Annotation[] anns = field.getDeclaredAnnotations();
      if(anns.length < 1)
        continue; // Not a db table column

      //判斷注解類型
      if(anns[0] instanceof SQLInteger) {
        SQLInteger sInt = (SQLInteger) anns[0];
        //獲取字段對應(yīng)列名稱,如果沒有就是使用字段名稱替代
        if(sInt.name().length() < 1)
          columnName = field.getName().toUpperCase();
        else
          columnName = sInt.name();
        //構(gòu)建語句
        columnDefs.add(columnName + " INT" +
                getConstraints(sInt.constraint()));
      }
      //判斷String類型
      if(anns[0] instanceof SQLString) {
        SQLString sString = (SQLString) anns[0];
        // Use field name if name not specified.
        if(sString.name().length() < 1)
          columnName = field.getName().toUpperCase();
        else
          columnName = sString.name();
        columnDefs.add(columnName + " VARCHAR(" +
                sString.value() + ")" +
                getConstraints(sString.constraint()));
      }
    }
    //數(shù)據(jù)庫表構(gòu)建語句
    StringBuilder createCommand = new StringBuilder(
            "CREATE TABLE " + tableName + "(");
    for(String columnDef : columnDefs)
      createCommand.append("\n    " + columnDef + ",");

    // Remove trailing comma
    String tableCreate = createCommand.substring(
            0, createCommand.length() - 1) + ");";
    return tableCreate;
  }

  /**
   * 判斷該字段是否有其他約束
   * @param con
   * @return
   */
  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;
  }

  public static void main(String[] args) throws Exception {
    String[] arg={"com.zejian.annotationdemo.Member"};
    for(String className : arg) {
      System.out.println("Table Creation SQL for " +
              className + " is :\n" + createTableSql(className));
    }
  }
}
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7
  • 8
  • 9
  • 10
  • 11
  • 12
  • 13
  • 14
  • 15
  • 16
  • 17
  • 18
  • 19
  • 20
  • 21
  • 22
  • 23
  • 24
  • 25
  • 26
  • 27
  • 28
  • 29
  • 30
  • 31
  • 32
  • 33
  • 34
  • 35
  • 36
  • 37
  • 38
  • 39
  • 40
  • 41
  • 42
  • 43
  • 44
  • 45
  • 46
  • 47
  • 48
  • 49
  • 50
  • 51
  • 52
  • 53
  • 54
  • 55
  • 56
  • 57
  • 58
  • 59
  • 60
  • 61
  • 62
  • 63
  • 64
  • 65
  • 66
  • 67
  • 68
  • 69
  • 70
  • 71
  • 72
  • 73
  • 74
  • 75
  • 76
  • 77
  • 78
  • 79
  • 80
  • 81
  • 82
  • 83
  • 84
  • 85

輸出結(jié)果為:

Table Creation SQL for com.zejian.annotationdemo.Member is :
CREATE TABLE MEMBER(
        ID VARCHAR(50) NOT NULL PRIMARY KEY,
        NAME VARCHAR(30) NOT NULL,
        AGE INT NOT NULL,
        DESCRIPTION VARCHAR(150)
        );
  • 1
  • 2
  • 3
  • 4
  • 5
  • 6
  • 7

常用場景

Annotation,特別是自定義注解,一般是在構(gòu)建框架或者通用庫時候使用的較多。下面列出了些我知道的,其他的歡迎補(bǔ)充。

Spring框架:解耦神器。
JUnit :測試框架
ButterKnife :在Android中使用的視圖注解框架,Android的小伙伴們都知道。
Dagger2 :依賴注入框架,在Android中用的也比較多。
Retrofit :Http網(wǎng)絡(luò)訪問框架,Android網(wǎng)絡(luò)請求標(biāo)配。
Room :Google 發(fā)布的用于Android開發(fā)的本地數(shù)據(jù)庫解決方案庫。

參考文章:深入理解Java注解類型(@Annotation)
《瘋狂Java講義》
《Think in java》

    本站是提供個人知識管理的網(wǎng)絡(luò)存儲空間,所有內(nèi)容均由用戶發(fā)布,不代表本站觀點。請注意甄別內(nèi)容中的聯(lián)系方式、誘導(dǎo)購買等信息,謹(jǐn)防詐騙。如發(fā)現(xiàn)有害或侵權(quán)內(nèi)容,請點擊一鍵舉報。
    轉(zhuǎn)藏 分享 獻(xiàn)花(0

    0條評論

    發(fā)表

    請遵守用戶 評論公約

    類似文章 更多