<kbd id="afajh"><form id="afajh"></form></kbd>
<strong id="afajh"><dl id="afajh"></dl></strong>
    <del id="afajh"><form id="afajh"></form></del>
        1. <th id="afajh"><progress id="afajh"></progress></th>
          <b id="afajh"><abbr id="afajh"></abbr></b>
          <th id="afajh"><progress id="afajh"></progress></th>

          你不知道的 Java 注解那些事!

          共 2051字,需瀏覽 5分鐘

           ·

          2019-08-24 10:43


          戳上方藍(lán)字 “程序猿雜貨鋪” 關(guān)注我 并?置頂星標(biāo)

          你的關(guān)注意義重大!

          原文 |?http://1t.click/JpS


          注解對(duì)于開(kāi)發(fā)人員來(lái)講既熟悉又陌生,熟悉是因?yàn)橹灰闶亲鲩_(kāi)發(fā),都會(huì)用到注解(常見(jiàn)的 @Override),陌生是因?yàn)榧词共皇褂米⒔庖舱粘D軌蜻M(jìn)行開(kāi)發(fā),注解不是必須的,但了解注解有助于我們深入理解某些第三方框架(比如 Android Support Annotations、JUnit、xUtils、ActiveAndroid 等),提高工作效率。

          Java 注解又稱為標(biāo)注,是 Java 從 1.5 開(kāi)始支持加入源碼的特殊語(yǔ)法元數(shù)據(jù):Java中的類、方法、變量、參數(shù)、包都可以被注解。這里提到的元數(shù)據(jù)是描述數(shù)據(jù)的數(shù)據(jù),結(jié)合實(shí)例來(lái)說(shuō)明:

          1. name="app_name">AnnotionDemo

          這里的 "app_name" 就是描述數(shù)據(jù) "AnnotionDemo" 的數(shù)據(jù),這是在配置文件中寫(xiě)的,注解是在源碼中寫(xiě)的,如下所示:

          1. @Override

          2. protectedvoid onCreate(Bundle savedInstanceState){

          3. super.onCreate(savedInstanceState);

          4. setContentView(R.layout.activity_main_layout);

          5. newThread(newRunnable(){

          6. @Override

          7. publicvoid run(){

          8. setTextInOtherThread();

          9. }

          10. }).start();

          11. }

          在上面的代碼中,在 MainActivity.java 中復(fù)寫(xiě)了父類 Activity.java 的 onCreate 方法,使用到了 @Override 注解。但即使不加上 @Override 注解標(biāo)記代碼,程序也能夠正常運(yùn)行。那這里的 @Override 注解有什么用呢?使用它有什么好處?事實(shí)上,@Override 是告訴編譯器這個(gè)方法是一個(gè)重寫(xiě)方法,如果父類中不存在該方法,編譯器會(huì)報(bào)錯(cuò),提示該方法不是父類中的方法。如果不小心拼寫(xiě)錯(cuò)誤,將 onCreate 寫(xiě)成了 onCreat,而且沒(méi)有使用@Override 注解,程序依然能夠編譯通過(guò),但運(yùn)行結(jié)果和期望的大不相同。從示例可以看出,注解有助于閱讀代碼

          使用注解很簡(jiǎn)單,根據(jù)注解類的 @Target 所修飾的對(duì)象范圍,可以在類、方法、變量、參數(shù)、包中使用 “@+注解類名 + [屬性值]” 的方式使用注解。比如:

          1. @UiThread

          2. privatevoid setTextInOtherThread(@StringResint resId){

          3. TextView threadTxtView =(TextView)MainActivity.this.findViewById(R.id.threadTxtViewId);

          4. threadTxtView.setText(resId);

          5. }

          特別說(shuō)明:

          • 注解僅僅是元數(shù)據(jù),和業(yè)務(wù)邏輯無(wú)關(guān),所以當(dāng)你查看注解類時(shí),發(fā)現(xiàn)里面沒(méi)有任何邏輯處理;

          • javadoc 中的 @author、@version、@param、@return、@deprecated、@hide、@throws、@exception、@see 是標(biāo)記,并不是注解;


          注解的作用


          • 格式檢查:告訴編譯器信息,比如被 @Override 標(biāo)記的方法如果不是父類的某個(gè)方法,IDE 會(huì)報(bào)錯(cuò);

          • 減少配置:運(yùn)行時(shí)動(dòng)態(tài)處理,得到注解信息,實(shí)現(xiàn)代替配置文件的功能;

          • 減少重復(fù)工作:比如第三方框架 xUtils,通過(guò)注解 @ViewInject 減少對(duì) findViewById 的調(diào)用,類似的還有(JUnit、ActiveAndroid 等);


          注解是如何工作的?


          注解僅僅是元數(shù)據(jù),和業(yè)務(wù)邏輯無(wú)關(guān),所以當(dāng)你查看注解類時(shí),發(fā)現(xiàn)里面沒(méi)有任何邏輯處理,eg:

          1. @Target(ElementType.FIELD)

          2. @Retention(RetentionPolicy.RUNTIME)

          3. public@interfaceViewInject{


          4. int value();


          5. /* parent view id */

          6. int parentId()default0;

          7. }

          如果注解不包含業(yè)務(wù)邏輯處理,必然有人來(lái)實(shí)現(xiàn)這些邏輯。注解的邏輯實(shí)現(xiàn)是元數(shù)據(jù)的用戶來(lái)處理的,注解僅僅提供它定義的屬性(類/方法/變量/參數(shù)/包)的信息,注解的用戶來(lái)讀取這些信息并實(shí)現(xiàn)必要的邏輯。當(dāng)使用java中的注解時(shí)(比如 @Override、@Deprecated、@SuppressWarnings)JVM 就是用戶,它在字節(jié)碼層面工作。如果是自定義的注解,比如第三方框架ActiveAndroid,它的用戶是每個(gè)使用注解的類,所有使用注解的類都需要繼承 Model.java,在 Model.java 的構(gòu)造方法中通過(guò)反射來(lái)獲取注解類中的每個(gè)屬性:

          1. publicTableInfo(ClassextendsModel> type){

          2. mType = type;


          3. finalTable tableAnnotation = type.getAnnotation(Table.class);


          4. if(tableAnnotation !=null){

          5. mTableName = tableAnnotation.name();

          6. mIdName = tableAnnotation.id();

          7. }

          8. else{

          9. mTableName = type.getSimpleName();

          10. }


          11. // Manually add the id column since it is not declared like the other columns.

          12. Field idField = getIdField(type);

          13. mColumnNames.put(idField, mIdName);


          14. List<Field> fields =newLinkedList<Field>(ReflectionUtils.getDeclaredColumnFields(type));

          15. Collections.reverse(fields);


          16. for(Field field : fields){

          17. if(field.isAnnotationPresent(Column.class)){

          18. finalColumn columnAnnotation = field.getAnnotation(Column.class);

          19. String columnName = columnAnnotation.name();

          20. if(TextUtils.isEmpty(columnName)){

          21. columnName = field.getName();

          22. }


          23. mColumnNames.put(field, columnName);

          24. }

          25. }


          26. }


          注解和配置文件的區(qū)別


          通過(guò)上面的描述可以發(fā)現(xiàn),其實(shí)注解干的很多事情,通過(guò)配置文件也可以干,比如為類設(shè)置配置屬性;但注解和配置文件是有很多區(qū)別的,在實(shí)際編程過(guò)程中,注解和配置文件配合使用在工作效率、低耦合、可拓展性方面才會(huì)達(dá)到權(quán)衡。

          配置文件:

          使用場(chǎng)合:

          • 外部依賴的配置,比如 build.gradle 中的依賴配置;

          • 同一項(xiàng)目團(tuán)隊(duì)內(nèi)部達(dá)成一致的時(shí)候;

          • 非代碼類的資源文件(比如圖片、布局、數(shù)據(jù)、簽名文件等);

          優(yōu)點(diǎn):

          • 降低耦合,配置集中,容易擴(kuò)展,比如 Android 應(yīng)用多語(yǔ)言支持;

          • 對(duì)象之間的關(guān)系一目了然,比如 strings.xml;

          • xml 配置文件比注解功能齊全,支持的類型更多,比如 drawable、style等;

          缺點(diǎn):

          • 繁瑣;

          • 類型不安全,比如 R.java 中的都是資源 ID,用 TextView 的 setText 方法時(shí)傳入 int 值時(shí)無(wú)法檢測(cè)出該值是否為資源 ID,但 @StringRes 可以;

          注解:

          使用場(chǎng)合:

          • 動(dòng)態(tài)配置信息;

          • 代為實(shí)現(xiàn)程序邏輯(比如 xUtils 中的 @ViewInject 代為實(shí)現(xiàn) findViewById);

          • 代碼格式檢查,比如 Override、Deprecated、NonNull、StringRes 等,便于 IDE 能夠檢查出代碼錯(cuò)誤;

          優(yōu)點(diǎn):

          • 在 class 文件中,提高程序的內(nèi)聚性;

          • 減少重復(fù)工作,提高開(kāi)發(fā)效率,比如 findViewById。

          缺點(diǎn):

          • 如果對(duì) annotation 進(jìn)行修改,需要重新編譯整個(gè)工程;

          • 業(yè)務(wù)類之間的關(guān)系不如 XML 配置那樣一目了然;

          • 程序中過(guò)多的 annotation,對(duì)于代碼的簡(jiǎn)潔度有一定影響;

          • 擴(kuò)展性較差;


          自定義注解


          通過(guò)閱讀注解類的源碼可以發(fā)現(xiàn),任何一個(gè)注解類都有如下特征:

          • 注解類會(huì)被 @interface 標(biāo)記;

          • 注解類的頂部會(huì)被 @Documented、@Retention、@Target、@Inherited 這四個(gè)注解標(biāo)記(@Documented、@Inherited可選,@Retention、@Target必須要有);

          @UiThread 源碼:

          1. @Documented

          2. @Retention(CLASS)

          3. @Target({METHOD,CONSTRUCTOR,TYPE})

          4. public@interfaceUiThread{

          5. }

          元注解

          上文提到的四個(gè)注解:@Documented、@Retention、@Target、@Inherited就是元注解,它們的作用是負(fù)責(zé)注解其它注解,主要是描述注解的一些屬性,任何注解都離不開(kāi)元注解(包括元注解自身,通過(guò)元注解可以自定義注解),元注解的用戶是 JDK,JDK 已經(jīng)幫助我們實(shí)現(xiàn)了這四個(gè)注解的邏輯。這四個(gè)注解在 JDK 的java.lang.annotation 包中。對(duì)每個(gè)元注解的詳細(xì)說(shuō)明如下:

          @Target


          作用:用于描述注解的使用范圍,即被描述的注解可以用在什么地方;

          取值:

          1、CONSTRUCTOR:構(gòu)造器;

          2、FIELD:實(shí)例;

          3、LOCAL_VARIABLE:局部變量;

          4、METHOD:方法;

          5、PACKAGE:包;

          6、PARAMETER:參數(shù);

          7、TYPE:類、接口(包括注解類型) 或enum聲明。

          示例:

          1. /***

          2. *

          3. * 實(shí)體注解接口

          4. */

          5. @Target(value ={ElementType.TYPE})

          6. @Retention(value =RetentionPolicy.RUNTIME)

          7. public@interfaceEntity{

          8. /***

          9. * 實(shí)體默認(rèn)firstLevelCache屬性為false

          10. * @return boolean

          11. */

          12. boolean firstLevelCache()defaultfalse;

          13. /***

          14. * 實(shí)體默認(rèn)secondLevelCache屬性為false

          15. * @return boolean

          16. */

          17. boolean secondLevelCache()defaulttrue;

          18. /***

          19. * 表名默認(rèn)為空

          20. * @return String

          21. */

          22. String tableName()default"";

          23. /***

          24. * 默認(rèn)以""分割注解

          25. */

          26. String split()default"";

          27. }


          @Retention


          作用:表示需要在什么級(jí)別保存該注解信息,用于描述注解的生命周期,即被描述的注解在什么范圍內(nèi)有效;

          取值:

          1、SOURCE:在源文件中有效,即源文件保留;

          2、CLASS:在class文件中有效,即class保留;

          3、RUNTIME:在運(yùn)行時(shí)有效,即運(yùn)行時(shí)保留;

          示例:

          1. /***

          2. * 字段注解接口

          3. */

          4. @Target(value ={ElementType.FIELD})//注解可以被添加在實(shí)例上

          5. @Retention(value =RetentionPolicy.RUNTIME)//注解保存在JVM運(yùn)行時(shí)刻,能夠在運(yùn)行時(shí)刻通過(guò)反射API來(lái)獲取到注解的信息

          6. public@interfaceColumn{

          7. String name();//注解的name屬性

          8. }


          @Documented


          作用:用于描述其它類型的 annotation 應(yīng)該被作為被標(biāo)注的程序成員的公共 API,因此可以被例如 javadoc 此類的工具文檔化。

          取值:它屬于標(biāo)記注解,沒(méi)有成員;

          示例:

          1. @Documented

          2. @Retention(CLASS)

          3. @Target({METHOD,CONSTRUCTOR,TYPE})

          4. public@interfaceUiThread{

          5. }


          @Inherited


          作用:用于描述某個(gè)被標(biāo)注的類型是可被繼承的。如果一個(gè)使用了 @Inherited 修飾的 annotation 類型被用于一個(gè) class,則這個(gè) annotation 將被用于該class的子類。

          取值:它屬于標(biāo)記注解,沒(méi)有成員;

          示例:

          1. /**

          2. * @author wangsheng

          3. **/

          4. @Inherited

          5. public@interfaceGreeting{

          6. publicenumFontColor{ BULE,RED,GREEN};

          7. String name();

          8. FontColor fontColor()defaultFontColor.GREEN;

          9. }


          如何自定義注解

          使用 @interface 自定義注解時(shí),自動(dòng)繼承了 java.lang.annotation.Annotation 接口,由編譯程序自動(dòng)完成其他細(xì)節(jié)。在定義注解時(shí),不能繼承其他的注解或接口。@interface 用來(lái)聲明一個(gè)注解,其中的每一個(gè)方法實(shí)際上是聲明了一個(gè)配置參數(shù)。方法的名稱就是參數(shù)的名稱,返回值類型就是參數(shù)的類型(返回值類型只能是基本類型、Class、String、enum)。可以通過(guò) default 來(lái)聲明參數(shù)的默認(rèn)值。

          自定義注解格式


          1. 元注解

          2. public@interface注解名{

          3. 定義體;

          4. }


          注解參數(shù)可支持的數(shù)據(jù)類型


          1、所有基本數(shù)據(jù)類型(int,float,boolean,byte,double,char,long,short);

          2、String 類型;

          3、Class 類型;

          4、enum 類型;

          5、Annotation 類型;

          6、以上所有類型的數(shù)組。


          特別說(shuō)明:

          1、注解類中的方法只能用 public 或者默認(rèn)這兩個(gè)訪問(wèn)權(quán)修飾,不寫(xiě) public 就是默認(rèn),eg:

          1. @Target(ElementType.FIELD)

          2. @Retention(RetentionPolicy.RUNTIME)

          3. @Documented

          4. public@interfaceFruitColor{

          5. publicenumColor{ BULE,RED,GREEN};

          6. Color fruitColor()defaultColor.GREEN;

          7. }

          2、如果注解類中只有一個(gè)成員,最好把方法名設(shè)置為"value",比如:

          1. @Target(ElementType.FIELD)

          2. @Retention(RetentionPolicy.RUNTIME)

          3. @Documented

          4. public@interfaceFruitName{

          5. String value()default"";

          6. }

          3、注解元素必須有確定的值,要么在定義注解的默認(rèn)值中指定,要么在使用注解時(shí)指定,非基本類型的注解元素的值不可為 null。因此, 使用空字符串或0作為默認(rèn)值是一種常用的做法。

          實(shí)例演示


          ToDo.java:注解類

          1. @Target(ElementType.METHOD)

          2. @Retention(RetentionPolicy.RUNTIME)

          3. @interfaceTodo{

          4. publicenumPriority{LOW, MEDIUM, HIGH}

          5. publicenumStatus{STARTED, NOT_STARTED}

          6. String author()default"Yash";

          7. Priority priority()defaultPriority.LOW;

          8. Status status()defaultStatus.NOT_STARTED;

          9. }

          BusinessLogic:使用注解的類

          1. publicclassBusinessLogic{

          2. publicBusinessLogic(){

          3. super();

          4. }


          5. publicvoid compltedMethod(){

          6. System.out.println("This method is complete");

          7. }


          8. @Todo(priority =Todo.Priority.HIGH)

          9. publicvoid notYetStartedMethod(){

          10. // No Code Written yet

          11. }


          12. @Todo(priority =Todo.Priority.MEDIUM, author ="Uday", status =Todo.Status.STARTED)

          13. publicvoid incompleteMethod1(){

          14. //Some business logic is written

          15. //But its not complete yet

          16. }


          17. @Todo(priority =Todo.Priority.LOW, status =Todo.Status.STARTED )

          18. publicvoid incompleteMethod2(){

          19. //Some business logic is written

          20. //But its not complete yet

          21. }

          22. }

          TodoReport.java:解析注解信息

          1. publicclassTodoReport{

          2. publicTodoReport(){

          3. super();

          4. }


          5. publicstaticvoid main(String[] args){

          6. getTodoReportForBusinessLogic();

          7. }


          8. /**

          9. * 解析使用注解的類,獲取通過(guò)注解設(shè)置的屬性

          10. */

          11. privatestaticvoid getTodoReportForBusinessLogic(){

          12. Class businessLogicClass =BusinessLogic.class;

          13. for(Method method : businessLogicClass.getMethods()){

          14. Todo todoAnnotation =(Todo)method.getAnnotation(Todo.class);

          15. if(todoAnnotation !=null){

          16. System.out.println(" Method Name : "+ method.getName());

          17. System.out.println(" Author : "+ todoAnnotation.author());

          18. System.out.println(" Priority : "+ todoAnnotation.priority());

          19. System.out.println(" Status : "+ todoAnnotation.status());

          20. System.out.println(" --------------------------- ");

          21. }

          22. }

          23. }

          24. }

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

          c68d1ec24fd9afea31373af669078abd.webp

          推薦閱讀


          0e86e6e93672a4f1fd09af88d507336d.webp

          0c26eda724278c2a0a83d62195346ecc.webp

          0cab3f29b7d1092396c19ae35cee66d3.webp


          如果這篇文章對(duì)你有幫助

          請(qǐng)幫忙轉(zhuǎn)發(fā),點(diǎn)個(gè)在看

          瀏覽 56
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          評(píng)論
          圖片
          表情
          推薦
          點(diǎn)贊
          評(píng)論
          收藏
          分享

          手機(jī)掃一掃分享

          分享
          舉報(bào)
          <kbd id="afajh"><form id="afajh"></form></kbd>
          <strong id="afajh"><dl id="afajh"></dl></strong>
            <del id="afajh"><form id="afajh"></form></del>
                1. <th id="afajh"><progress id="afajh"></progress></th>
                  <b id="afajh"><abbr id="afajh"></abbr></b>
                  <th id="afajh"><progress id="afajh"></progress></th>
                  国产熟女精品视频 | 69亚洲| 亚洲热在线 | 亚洲第一成人在线视频 | 热久久免费在线视频 |