<output id="qn6qe"></output>

    1. <output id="qn6qe"><tt id="qn6qe"></tt></output>
    2. <strike id="qn6qe"></strike>

      亚洲 日本 欧洲 欧美 视频,日韩中文字幕有码av,一本一道av中文字幕无码,国产线播放免费人成视频播放,人妻少妇偷人无码视频,日夜啪啪一区二区三区,国产尤物精品自在拍视频首页,久热这里只有精品12

      安卓筆記俠

      專注安卓開發(fā)

      導(dǎo)航

      Java注解處理器--編譯時處理的注解

      1. 一些基本概念

      在開始之前,我們需要聲明一件重要的事情是:我們不是在討論在運行時通過反射機(jī)制運行處理的注解,而是在討論在編譯時處理的注解。
      注解處理器是 javac 自帶的一個工具,用來在編譯時期掃描處理注解信息。你可以為某些注解注冊自己的注解處理器。這里,我假設(shè)你已經(jīng)了解什么是注解及如何自定義注解。如果你還未了解注解的話,可以查看官方文檔。注解處理器在 Java 5 的時候就已經(jīng)存在了,但直到 Java 6 (發(fā)布于2006看十二月)的時候才有可用的API。過了一段時間java的使用者們才意識到注解處理器的強(qiáng)大。所以最近幾年它才開始流行。
      一個特定注解的處理器以 java 源代碼(或者已編譯的字節(jié)碼)作為輸入,然后生成一些文件(通常是.java文件)作為輸出。那意味著什么呢?你可以生成 java 代碼!這些 java 代碼在生成的.java文件中。因此你不能改變已經(jīng)存在的java類,例如添加一個方法。這些生成的 java 文件跟其他手動編寫的 java 源代碼一樣,將會被 javac 編譯。

      Annotation processing是在編譯階段執(zhí)行的,它的原理就是讀入Java源代碼,解析注解,然后生成新的Java代碼。新生成的Java代碼最后被編譯成Java字節(jié)碼,注解解析器(Annotation Processor)不能改變讀入的Java 類,比如不能加入或刪除Java方法。

      2. AbstractProcessor

      讓我們來看一下處理器的 API。所有的處理器都繼承了AbstractProcessor,如下所示:

       1 package com.example;
       2 
       3 import java.util.LinkedHashSet;
       4 import java.util.Set;
       5 import javax.annotation.processing.AbstractProcessor;
       6 import javax.annotation.processing.ProcessingEnvironment;
       7 import javax.annotation.processing.RoundEnvironment;
       8 import javax.annotation.processing.SupportedAnnotationTypes;
       9 import javax.annotation.processing.SupportedSourceVersion;
      10 import javax.lang.model.SourceVersion;
      11 import javax.lang.model.element.TypeElement;
      12 
      13 public class MyProcessor extends AbstractProcessor {
      14 
      15     @Override
      16     public boolean process(Set<? extends TypeElement> annoations,
      17             RoundEnvironment env) {
      18         return false;
      19     }
      20 
      21     @Override
      22     public Set<String> getSupportedAnnotationTypes() {
      23         Set<String> annotataions = new LinkedHashSet<String>();
      24         annotataions.add("com.example.MyAnnotation");
      25         return annotataions;
      26     }
      27 
      28     @Override
      29     public SourceVersion getSupportedSourceVersion() {
      30         return SourceVersion.latestSupported();
      31     }
      32 
      33     @Override
      34     public synchronized void init(ProcessingEnvironment processingEnv) {
      35         super.init(processingEnv);
      36     }
      37 
      38 }
      • init(ProcessingEnvironment processingEnv) :所有的注解處理器類都必須有一個無參構(gòu)造函數(shù)。然而,有一個特殊的方法init(),它會被注解處理工具調(diào)用,以ProcessingEnvironment作為參數(shù)。ProcessingEnvironment 提供了一些實用的工具類ElementsTypesFiler。我們在后面將會使用到它們。

      • process(Set<? extends TypeElement> annoations, RoundEnvironment env) :這類似于每個處理器的main()方法。你可以在這個方法里面編碼實現(xiàn)掃描,處理注解,生成 java 文件。使用RoundEnvironment 參數(shù),你可以查詢被特定注解標(biāo)注的元素(原文:you can query for elements annotated with a certain annotation )。后面我們將會看到詳細(xì)內(nèi)容。

      • getSupportedAnnotationTypes():在這個方法里面你必須指定哪些注解應(yīng)該被注解處理器注冊。注意,它的返回值是一個String集合,包含了你的注解處理器想要處理的注解類型的全稱。換句話說,你在這里定義你的注解處理器要處理哪些注解。

      • getSupportedSourceVersion() : 用來指定你使用的 java 版本。通常你應(yīng)該返回SourceVersion.latestSupported() 。不過,如果你有足夠的理由堅持用 java 6 的話,你也可以返回SourceVersion.RELEASE_6。我建議使用SourceVersion.latestSupported()。在 Java 7 中,你也可以使用注解的方式來替代重寫getSupportedAnnotationTypes() 和 getSupportedSourceVersion(),如下所示:

      @SupportedSourceVersion(value=SourceVersion.RELEASE_7)
      @SupportedAnnotationTypes({
         // Set of full qullified annotation type names
          "com.example.MyAnnotation",
          "com.example.AnotherAnnotation"
       })
      public class MyProcessor extends AbstractProcessor {
      
          @Override
          public boolean process(Set<? extends TypeElement> annoations,
                  RoundEnvironment env) {
              return false;
          }
          @Override
          public synchronized void init(ProcessingEnvironment processingEnv) {
              super.init(processingEnv);
          }
      }

      由于兼容性問題,特別是對于 android ,我建議重寫getSupportedAnnotationTypes() 和 getSupportedSourceVersion() ,而不是使用 @SupportedAnnotationTypes 和 @SupportedSourceVersion

      接下來你必須知道的事情是:注解處理器運行在它自己的 JVM 中。是的,你沒看錯。javac 啟動了一個完整的 java 虛擬機(jī)來運行注解處理器。這意味著什么?你可以使用任何你在普通 java 程序中使用的東西。使用 guava! 你可以使用依賴注入工具,比如dagger或者任何其他你想使用的類庫。但不要忘記,即使只是一個小小的處理器,你也應(yīng)該注意使用高效的算法及設(shè)計模式,就像你在開發(fā)其他 java 程序中所做的一樣。

      3. 注冊你的處理器

      你可能會問 “怎樣注冊我的注解處理器到 javac ?”。你必須提供一個.jar文件。就像其他 .jar 文件一樣,你將你已經(jīng)編譯好的注解處理器打包到此文件中。并且,在你的 .jar 文件中,你必須打包一個特殊的文件javax.annotation.processing.ProcessorMETA-INF/services目錄下。因此你的 .jar 文件目錄結(jié)構(gòu)看起來就你這樣:

      MyProcess.jar
          -com
              -example
                  -MyProcess.class
          -META-INF
              -services
                  -javax.annotation.processing.Processor

      javax.annotation.processing.Processor 文件的內(nèi)容是一個列表,每一行是一個注解處理器的全稱。例如:

      com.example.MyProcess
      com.example.AnotherProcess


      4. 例子:工廠模式

      我們要解決的問題是:我們要實現(xiàn)一個 pizza 店,這個 pizza 店提供給顧客兩種 pizza (Margherita 和 Calzone),還有甜點 Tiramisu(提拉米蘇)。

       1 public interface Meal {
       2     public float getPrice();
       3 }
       4 public class MargheritaPizza implements Meal{
       5     @Override
       6     public float getPrice() {
       7         return 6.0f;
       8     }
       9 }
      10 public class CalzonePizza implements Meal{
      11     @Override
      12     public float getPrice() {
      13         return 8.5f;
      14     }
      15 }
      16 public class Tiramisu implements Meal{
      17     @Override
      18     public float getPrice() {
      19         return 4.5f;
      20     }
      21 }
      22 
      23 public class PizzaStore {
      24 
      25     public Meal order(String mealName) {
      26         if (null == mealName) {
      27             throw new IllegalArgumentException("name of meal is null!");
      28         }
      29         if ("Margherita".equals(mealName)) {
      30             return new MargheritaPizza();
      31         }
      32 
      33         if ("Calzone".equals(mealName)) {
      34             return new CalzonePizza();
      35         }
      36 
      37         if ("Tiramisu".equals(mealName)) {
      38             return new Tiramisu();
      39         }
      40 
      41         throw new IllegalArgumentException("Unknown meal '" + mealName + "'");
      42     }
      43 
      44     private static String readConsole() {
      45         Scanner scanner = new Scanner(System.in);
      46         String meal = scanner.nextLine();
      47         scanner.close();
      48         return meal;
      49     }
      50     
      51     public static void main(String[] args) {
      52         System.out.println("welcome to pizza store");
      53         PizzaStore pizzaStore = new PizzaStore();
      54         Meal meal = pizzaStore.order(readConsole());
      55         System.out.println("Bill:$" + meal.getPrice());
      56     }
      57 }

      正如你所見,在order()方法中,我們有許多 if 條件判斷語句。并且,如果我們添加一種新的 pizza 的話,我們就得添加一個新的 if 條件判斷。但是等一下,使用注解處理器和工廠模式,我們可以讓一個注解處理器生成這些 if 語句。如此一來,我們想要的代碼就像這樣子:

       1 public class PizzaStore {
       2 
       3     private MealFactory factory = new MealFactory();
       4     
       5     public Meal order(String mealName) {
       6         return factory.create(mealName);
       7     }
       8 
       9     private static String readConsole() {
      10         Scanner scanner = new Scanner(System.in);
      11         String meal = scanner.nextLine();
      12         scanner.close();
      13         return meal;
      14     }
      15     
      16     public static void main(String[] args) {
      17         System.out.println("welcome to pizza store");
      18         PizzaStore pizzaStore = new PizzaStore();
      19         Meal meal = pizzaStore.order(readConsole());
      20         System.out.println("Bill:$" + meal.getPrice());
      21     }
      22 }
      23 
      24 public class MealFactory {
      25 
      26     public Meal create(String id) {
      27         if (id == null) {
      28             throw new IllegalArgumentException("id is null!");
      29         }
      30         if ("Calzone".equals(id)) {
      31             return new CalzonePizza();
      32         }
      33 
      34         if ("Tiramisu".equals(id)) {
      35             return new Tiramisu();
      36         }
      37 
      38         if ("Margherita".equals(id)) {
      39             return new MargheritaPizza();
      40         }
      41 
      42         throw new IllegalArgumentException("Unknown id = " + id);
      43     }
      44 }

      5. @Factory Annotation

      能猜到么,我們打算使用注解處理器生成MealFactory類。更一般的說,我們想要提供一個注解和一個處理器用來生成工廠類。
      讓我們看一下@Factory注解:

      @Target(ElementType.TYPE)
      @Retention(RetentionPolicy.CLASS)
      public @interface Factory {
      
          /**
           * The name of the factory
           */
          Class<?> type();
      
          /**
           * The identifier for determining which item should be instantiated
           */
          String id();
      }

      思想是這樣的:我們注解那些食物類,使用type()表示這個類屬于哪個工廠,使用id()表示這個類的具體類型。讓我們將@Factory注解應(yīng)用到這些類上吧:

       1 @Factory(type=MargheritaPizza.class, id="Margherita")
       2 public class MargheritaPizza implements Meal{
       3 
       4     @Override
       5     public float getPrice() {
       6         return 6.0f;
       7     }
       8 }
       9 
      10 @Factory(type=CalzonePizza.class, id="Calzone")
      11 public class CalzonePizza implements Meal{
      12 
      13     @Override
      14     public float getPrice() {
      15         return 8.5f;
      16     }
      17 }
      18 
      19 @Factory(type=Tiramisu.class, id="Tiramisu")
      20 public class Tiramisu implements Meal{
      21 
      22     @Override
      23     public float getPrice() {
      24         return 4.5f;
      25     }
      26 }

      你可能會問,我們是不是可以只將@Factory注解應(yīng)用到Meal接口上?答案是不行,因為注解是不能被繼承的。即在class X上有注解,class Y extends X,那么class Y是不會繼承class X上的注解的。在我們編寫處理器之前,需要明確幾點規(guī)則:

      1. 只有類能夠被@Factory注解,因為接口和虛類是不能通過new操作符實例化的。
      2. @Factory注解的類必須提供一個默認(rèn)的無參構(gòu)造函數(shù)。否則,我們不能實例化一個對象。
      3. @Factory注解的類必須直接繼承或者間接繼承type指定的類型。(或者實現(xiàn)它,如果type指定的是一個接口)
      4. @Factory注解的類中,具有相同的type類型的話,這些類就會被組織起來生成一個工廠類。工廠類以Factory作為后綴,例如:type=Meal.class將會生成MealFactory類。
      5. id的值只能是字符串,且在它的type組中必須是唯一的。

      注解處理器:

       1 public class FactoryProcessor extends AbstractProcessor {
       2 
       3     private Types typeUtils;
       4     private Elements elementUtils;
       5     private Filer filer;
       6     private Messager messager;
       7     private Map<String, FactoryGroupedClasses> factoryClasses = 
       8             new LinkedHashMap<String, FactoryGroupedClasses>();
       9 
      10     @Override
      11     public synchronized void init(ProcessingEnvironment processingEnv) {
      12         super.init(processingEnv);
      13         typeUtils = processingEnv.getTypeUtils();
      14         elementUtils = processingEnv.getElementUtils();
      15         filer = processingEnv.getFiler();
      16         messager = processingEnv.getMessager();
      17     }
      18 
      19     @Override
      20     public boolean process(Set<? extends TypeElement> arg0,
      21             RoundEnvironment arg1) {
      22         ...
      23         return false;
      24     }
      25 
      26     @Override
      27     public Set<String> getSupportedAnnotationTypes() {
      28         Set<String> annotataions = new LinkedHashSet<String>();
      29         annotataions.add(Factory.class.getCanonicalName());
      30         return annotataions;
      31     }
      32 
      33     @Override
      34     public SourceVersion getSupportedSourceVersion() {
      35         return SourceVersion.latestSupported();
      36     }
      37 }

      getSupportedAnnotationTypes()方法中,我們指定@Factory注解將被這個處理器處理。

      posted on 2018-05-10 16:51  安卓筆記俠  閱讀(6421)  評論(0)    收藏  舉報

      主站蜘蛛池模板: 少妇伦子伦精品无吗| 国产精品亚洲А∨天堂免下载| 国产av一区二区三区久久| 蜜桃草视频免费在线观看| 国产最新精品系列第三页 | 成人区人妻精品一区二蜜臀| 欧美国产精品不卡在线观看| 国产精品一二二区视在线 | 一本大道久久香蕉成人网| 久久91精品牛牛| 国产成人欧美一区二区三区| 婷婷色综合成人成人网小说| 亚洲色大成网站www在线| 一本精品99久久精品77| 中文字幕第一页国产| 国内精品久久久久影院薰衣草 | 国产一区二区日韩经典| 大冶市| 国产成人亚洲日韩欧美| 国产午夜福利视频在线| 国产一级二级三级毛片| 欧美高清一区三区在线专区| 国产AV永久无码青青草原| 精品日韩人妻中文字幕| 双城市| 久久精品波多野结衣| 久久精品一本到99热免费| 97精品尹人久久大香线蕉| 九九热在线免费精品视频| 99久久精品国产免费看| 国产精品免费视频网站| 精品国产一区av天美传媒| 久久青青草原亚洲AV无码麻豆| 亚洲午夜精品毛片成人播放| 久久久久成人片免费观看蜜芽 | 午夜福利日本一区二区无码| 亚洲色无码播放亚洲成av| 日韩一区二区三区女优丝袜| 日韩精品卡一卡二卡三卡四 | 亚洲 小说区 图片区 都市| 亚洲欧美综合精品成人导航|