Compréhension des annotations Java

Un mot sur les annotations introduites pour la première fois dans le document officiel: les annotations Java sont utilisées pour fournir des métadonnées pour le code Java. En tant que métadonnées, les annotations n'affectent pas directement l'exécution de votre code, mais il existe certains types d'annotations qui peuvent être utilisées à cette fin. Les annotations Java ont été ajoutées à Java depuis Java5. Après avoir lu cette phrase, vous pouvez toujours être confus. Ensuite, j'apprendrai à nouveau sur les annotations à partir de la définition des annotations, des méta-annotations, des attributs d'annotation, des annotations personnalisées et de l'analyse des annotations fournies par le JDK.

Définition de l'annotation

  • Dans le développement quotidien de nouvelles classes Java, nous utilisons davantage la classe et l'interface, et les annotations, comme elles, sont également un type de classe. Le modificateur utilisé est @interface

Comment écrire des annotations

  • Nous créons une nouvelle annotation MyTestAnnotation
public @interface MyTestAnnotation {

}
  • Ensuite, nous pouvons appliquer l'annotation que nous venons de créer sur la classe ou la méthode
@MyTestAnnotation
public class test {
   @MyTestAnnotation
   public static void main(String[] args){
   }
}
  • Ci-dessus, nous venons d'apprendre à écrire des annotations, mais nous n'avons écrit aucun code dans les annotations que nous avons définies. Maintenant, cette annotation n'a plus de sens. Comment faire fonctionner l'annotation? Ensuite, nous passons à la compréhension des méta-annotations.

Annotation Meta

  • La méta-annotation, comme son nom l'indique, peut être comprise comme une annotation d'une annotation, qui agit dans une annotation pour nous faciliter l'utilisation d'une annotation pour atteindre la fonction souhaitée. Il existe cinq types de méta-annotations: @Retention, @Target, @Document, @Inherited et @Repeatable (ajoutées dans JDK1.8).

@Rétention

  • Le sens anglais de Retention signifie rétention et rétention. Cela signifie que l'étape d'existence de l'annotation est réservée dans le code source (période de compilation), le bytecode (chargement de classe) ou l'exécution (s'exécutant dans la JVM). Utilisez l'énumération RetentionPolicy dans l'annotation @Retention pour indiquer la période de rétention des annotations
  • @Retention (RetentionPolicy.SOURCE), l'annotation n'existe que dans le code source, non incluse dans le fichier bytecode de la classe
  • @Retention (RetentionPolicy.CLASS), la politique de rétention par défaut, les annotations existeront dans le fichier bytecode de la classe, mais ne pourront pas être obtenues au moment de l'exécution
  • @Retention (RetentionPolicy.RUNTIME), l'annotation existera dans le fichier bytecode de la classe et pourra être obtenue par réflexion au moment de l'exécution
  • Si nous sommes des annotations personnalisées, grâce à l'analyse précédente, nos annotations personnalisées ne fonctionneront pas si elles sont uniquement stockées dans le code source ou le fichier bytecode, et les annotations peuvent être obtenues pendant l'exécution pour atteindre notre objectif, donc des annotations personnalisées @Retention ( RetentionPolicy.RUNTIME) doit être utilisé dans
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTestAnnotation {

}

@Cible

  • Cible signifie cible en anglais, ce qui est également très facile à comprendre. L'utilisation de la méta-annotation @Target pour exprimer la portée de notre annotation est plus spécifique. Il peut s'agir d'une classe, d'une méthode, d'une variable de paramètre de méthode, etc., et c'est aussi exprimée via l'énumération elementType Types de
  • @Target (ElementType.TYPE) fonction interface, classe, énumération, annotation
  • @Target (ElementType.FIELD) Fonction du champ d'attribut et de la constante énumérée
  • Méthode de la fonction @Target (ElementType.METHOD)
  • @Target (ElementType.PARAMETER), paramètre de méthode de fonction
  • Constructeur de fonction @Target (ElementType.CONSTRUCTOR)
  • @Target (ElementType.LOCAL_VARIABLE) agit sur les variables locales
  • @Target (ElementType.ANNOTATION_TYPE) agit sur les annotations (les annotations @Retention utilisent cet attribut)
  • @Target (ElementType.PACKAGE) agit sur les packages
  • @Target (ElementType.TYPE_PARAMETER) agit sur les génériques de type, à savoir les méthodes génériques, les classes génériques, les interfaces génériques (ajout de jdk1.8)
  • Utilisation du type @Target (ElementType.TYPE_USE). Peut être utilisé pour annoter n'importe quel type sauf class (ajout de jdk1.8)
  • Le type ElementType.TYPE est généralement le plus couramment utilisé
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyTestAnnotation {

}

@Documenté

  • Document en anglais signifie document. Sa fonction est de pouvoir inclure les éléments dans les annotations dans le Javadoc.

@Hérité

  • Inherited signifie héritage en anglais, mais cet héritage est similaire à ce que nous comprenons habituellement. Une annotation annotée par @Inherited modifie une classe parente. Si sa sous-classe n'est pas modifiée par d'autres annotations, ses sous-classes héritent également de l'annotation de la classe parente.
  • Regardons un exemple d'annotation @Inherited
/**自定义注解*/
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyTestAnnotation {
}
/**父类标注自定义注解*/
@MyTestAnnotation
public class Father {
}
/**子类*/
public class Son extends Father {
}
/**测试子类获取父类自定义注解*/
public class test {
   public static void main(String[] args){

      //获取Son的class对象
       Class<Son> sonClass = Son.class;
      // 获取Son类上的注解MyTestAnnotation可以执行成功
      MyTestAnnotation annotation = sonClass.getAnnotation(MyTestAnnotation.class);
   }
}

@Répétable

  • Répétable en anglais signifie répétable. Comme son nom l'indique, l'annotation modifiée par cette méta-annotation peut agir sur un objet plusieurs fois en même temps, mais chaque fois que l'annotation est appliquée peut représenter des significations différentes.
  • Regardons un exemple de personne jouant à un jeu
/**一个人喜欢玩游戏,他喜欢玩英雄联盟,绝地求生,极品飞车,尘埃4等,则我们需要定义一个人的注解,他属性代表喜欢玩游戏集合,一个游戏注解,游戏属性代表游戏名称*/
/**玩家注解*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface People {
    Game[] value() ;
}
/**游戏注解*/
@Repeatable(People.class)
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface Game {
    String value() default "";
}
/**玩游戏类*/
@Game(value = "LOL")
@Game(value = "PUBG")
@Game(value = "NFS")
@Game(value = "Dirt4")
public class PlayGame {
}
  • A travers l'exemple ci-dessus, vous pouvez avoir une question, quelle est la variable entre parenthèses dans le commentaire du jeu, en fait, cela correspond à l'attribut défini dans le commentaire du jeu. Ensuite, nous continuons à apprendre les attributs des annotations.

Attributs annotés

  • À travers l'exemple d'annotation @Repeatable dans la section précédente, nous avons parlé des propriétés des annotations. Les attributs des annotations sont en fait similaires aux variables définies dans la classe, sauf que les variables dans les annotations sont toutes des variables membres (attributs), et il n'y a pas de méthodes dans les annotations, seulement des variables membres et les noms de variables sont les paramètres correspondants dans les crochets d'annotation Nom, valeur de retour de variable annotation type de paramètre correspondant entre parenthèses Je crois que cela vous donnera une meilleure compréhension de l'exemple ci-dessus. Le type de variable dans l'annotation @Repeatable est la classe générique correspondant à Annotation (interface).
/**注解Repeatable源码*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
    /**
     * Indicates the <em>containing annotation type</em> for the
     * repeatable annotation type.
     * @return the containing annotation type
     */
    Class<? extends Annotation> value();
}

L'essence de l'annotation

  • L'essence de l'annotation est une interface d'annotation
/**Annotation接口源码*/
public interface Annotation {

    boolean equals(Object obj);

    int hashCode();

    Class<? extends Annotation> annotationType();
}
  • Grâce au code source ci-dessus, nous savons que l'annotation elle-même est une sous-interface de l'interface Annotation, c'est-à-dire que l'annotation peut effectivement avoir des attributs et des méthodes, mais les attributs de l'interface sont statiques finaux, ce qui n'a aucune signification pour l'annotation, et nous définissons l'interface La méthode est équivalente à l'attribut de l'annotation, ce qui correspond à la raison pour laquelle l'annotation n'a que la variable membre d'attribut, en fait, c'est la méthode de l'interface, c'est pourquoi le La variable membre a des parenthèses , ce qui est différent de l'interface que nous pouvons donner entre parenthèses de l'affectation de la variable membre d'annotation.

Type d'attribut d'annotation

  • Les types d'attribut d'annotation peuvent avoir les types répertoriés ci-dessous
  • 1. Types de données de base
  • 2. chaîne
  • 3. Type d'énumération
  • 4. Type d'annotation
  • 5. type de classe
  • 6. Types de tableaux unidimensionnels des types ci-dessus

Annoter l'affectation des variables de membre

  • Si l'annotation a plusieurs attributs, vous pouvez utiliser "," dans les crochets d'annotation pour séparer les attributs correspondants afin d'attribuer des valeurs, comme dans l'exemple suivant, l'annotation attribue des attributs dans la classe parent
@Documented
@Inherited
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyTestAnnotation {
    String name() default "mao";
    int age() default 18;
}

@MyTestAnnotation(name = "father",age = 50)
public class Father {
}

Obtenir les attributs d'annotation

  • Plus tôt, nous avons expliqué comment définir de nombreuses annotations et où les placer. Nous pouvons maintenant commencer à apprendre l'extraction des attributs d'annotation. C'est la clé de l'utilisation des annotations. L'obtention de la valeur de l'attribut est le but de l'utilisation des annotations.
  • Si vous obtenez les attributs d'annotation, bien sûr, il s'agit de réflexion, il existe trois méthodes de base
/**是否存在对应 Annotation 对象*/
  public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
        return GenericDeclaration.super.isAnnotationPresent(annotationClass);
    }

 /**获取 Annotation 对象*/
    public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
        Objects.requireNonNull(annotationClass);

        return (A) annotationData().annotations.get(annotationClass);
    }
 /**获取所有 Annotation 对象数组*/   
 public Annotation[] getAnnotations() {
        return AnnotationParser.toArray(annotationData().annotations);
    }    

En combinant l'exemple précédent, obtenons les attributs d'annotation. Avant d'obtenir les annotations, nous devons utiliser la méta-annotation @Retention (RetentionPolicy.RUNTIME)

public class test {
   public static void main(String[] args) throws NoSuchMethodException {

        /**
         * 获取类注解属性
         */
        Class<Father> fatherClass = Father.class;
        boolean annotationPresent = fatherClass.isAnnotationPresent(MyTestAnnotation.class);
        if(annotationPresent){
            MyTestAnnotation annotation = fatherClass.getAnnotation(MyTestAnnotation.class);
            System.out.println(annotation.name());
            System.out.println(annotation.age());
        }

        /**
         * 获取方法注解属性
         */
        try {
            Field age = fatherClass.getDeclaredField("age");
            boolean annotationPresent1 = age.isAnnotationPresent(Age.class);
            if(annotationPresent1){
                Age annotation = age.getAnnotation(Age.class);
                System.out.println(annotation.value());
            }

            Method play = PlayGame.class.getDeclaredMethod("play");
            if (play!=null){
                People annotation2 = play.getAnnotation(People.class);
                Game[] value = annotation2.value();
                for (Game game : value) {
                    System.out.println(game.value());
                }
            }
        } catch (NoSuchFieldException e) {
            e.printStackTrace();
        }
    }
}

résultat de l'opération:

Annotations fournies par JDK

annotation effet Précautions
@Passer outre Il est utilisé pour décrire que la méthode actuelle est une méthode surchargée, et la méthode est vérifiée pendant la phase de compilation En jdk1.5, il ne peut décrire la réécriture qu'en héritage, et en jdk1.6, il peut décrire la réécriture de l'implémentation de l'interface et la réécriture de l'héritage des classes.
@Deprecated Il est utilisé pour décrire la méthode actuelle est une méthode obsolète non
@Supprimer les avertissements Supprimez l'avertissement dans le programme. non

Annotation et application

  • Maintenant, nous revenons à la description du document officiel au début

Les annotations Java sont utilisées pour fournir des métadonnées pour le code Java. En tant que métadonnées, les annotations n'affectent pas directement l'exécution de votre code, mais il existe certains types d'annotations qui peuvent être utilisées à cette fin.

  • Après notre compréhension précédente, les annotations sont en fait une chose très pratique. Il est temps de vivre et la zone d'action peut être facilement définie par vous. C'est juste une question de ce que vous utilisez les annotations.

Utiliser des annotations pour la configuration des paramètres

  • Prenons un exemple de virement bancaire. En supposant que la banque dispose d'un service de virement, la limite de virement peut changer en fonction de l'évolution du taux de change. Nous pouvons utiliser des annotations pour configurer de manière flexible la limite de virement au lieu de modifier notre code d'entreprise à chaque fois.
/**定义限额注解*/
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
public @interface BankTransferMoney {
    double maxMoney() default 10000;
}
/**转账处理业务类*/
public class BankService {
    /**
     * @param money 转账金额
     */
    @BankTransferMoney(maxMoney = 15000)
    public static void TransferMoney(double money){
        System.out.println(processAnnotationMoney(money));

    }
    private static String processAnnotationMoney(double money) {
        try {
            Method transferMoney = BankService.class.getDeclaredMethod("TransferMoney",double.class);
            boolean annotationPresent = transferMoney.isAnnotationPresent(BankTransferMoney.class);
            if(annotationPresent){
                BankTransferMoney annotation = transferMoney.getAnnotation(BankTransferMoney.class);
                double l = annotation.maxMoney();
                if(money>l){
                   return "转账金额大于限额,转账失败";
                }else {
                    return"转账金额为:"+money+",转账成功";
                }
            }
        } catch ( NoSuchMethodException e) {
            e.printStackTrace();
        }
        return "转账处理失败";
    }
    public static void main(String[] args){
        TransferMoney(10000);
    }
}

résultat de l'opération:

  • Grâce à l'exemple ci-dessus, tant que le taux de change change, nous pouvons modifier directement la limite maximale actuelle en modifiant la valeur de configuration de l'annotation.

Application du cadre tiers

  • En tant que développeur Android, les frameworks tiers ButterKnife, Retrofit2, Dagger2, etc. que nous utilisons habituellement ont des applications annotées. Si nous voulons comprendre les principes de ces frameworks, la connaissance de base des annotations est essentielle.

Le rôle des annotations

  • Fournissez des informations au compilateur: le compilateur peut utiliser des annotations pour détecter des erreurs ou des avertissements et imprimer des journaux.
  • Traitement pendant la phase de compilation: des outils logiciels peuvent être utilisés pour générer automatiquement du code, des documents ou tout autre traitement automatique correspondant à l'aide des informations d'annotation.
  • Traitement au moment de l'exécution: certaines annotations peuvent accepter l'extraction de code lorsque le programme est en cours d'exécution et effectuer automatiquement les opérations correspondantes.
  • Comme indiqué dans le document officiel, les annotations peuvent fournir des métadonnées. Dans l'exemple de transfert, le processus d'obtention des valeurs d'annotation est la logique d'extraction d'annotation écrite directement par nos développeurs. Le code de traitement de l'extraction et du traitement des annotations est collectivement appelé APT ( Outil de traitement des annotations).) . La méthode processAnnotationMoney de l'exemple de transfert ci-dessus peut être comprise comme une classe d'outils APT.

Je suppose que tu aimes

Origine blog.csdn.net/sun124608666/article/details/112969537
conseillé
Classement