Nous voyons souvent des choses comme "@Override", "@target" et ainsi de suite dans le code java. Qu'est-ce que c'est?
En Java, ce sont des "annotations".
Ce qui suit est l'explication de Baidu Encyclopedia: java.lang.annotation.Retention peut demander au compilateur de traiter votre annotation personnalisée lorsque vous définissez le modèle d'annotation. Le compilateur laissera des informations d'annotation dans les archives de classe, mais non lues par la machine virtuelle, mais ne fournira des informations que lorsque le compilateur ou le programme d'outils s'exécute.
En d'autres termes, les annotations sont basées sur des fichiers de classe et ont le même effet que les macros dans le langage C.
Il n'y a aucune trace d'annotation dans le fichier de classe.
La base de l'annotation est la réflexion. Par conséquent, l'annotation peut être comprise comme un concept unique à Java.
1. Meta Note
Dans le package java.lang.annotation, quatre "primitives" d'annotation ont été définies.
1). @ Target, utilisé pour clarifier le type en cours de modification: (méthodes, champs, classes, interfaces, etc.)
2). @ Rétention, décrit l'existence de l'annentation:
L'annotation RetentionPolicy.runtime existera dans le fichier de bytecode de classe et peut être obtenue par réflexion lors de l'exécution.
RetenderPolicy.classe la politique de rétention par défaut, l'annotation existera dans le fichier de bytecode de classe, mais il ne peut pas être obtenu pendant l'exécution.
L'annotation RetentionPolicy.
3). @ Documenté, par défaut, les annotations ne seront pas enregistrées dans Javadoc, mais cette annotation peut être utilisée pour indiquer que cette annotation doit être enregistrée.
4). @ La méta-annotation héréditaire est une annotation de balise, et @inherited explique qu'un certain type annoté est hérité.
Si un type d'annotation utilisant la modification @inherited est utilisé pour une classe, l'annotation sera utilisée pour une sous-classe de la classe.
2. Annotations personnalisées
package com.joyfulmath.jvmexample.annnotaion; import java.lang.annotation.elementType; import java.lang.annotation.retention; import java.lang.annotation.retentionpolicy; import java.lang.annotation.target; / *** @Autor DeMan.lu * @version sur 2016-05-23 13:36 * / @ Target (elementType.field) @retention (retenderPolicy.runtime) public @Interface FruitName {String Value () Default "";} Tout d'abord, une annotation nécessite généralement 2 modifications de méta-annotation:
@Target (elementType.field)
@Retention (RetentionPolicy.runtime)
Les fonctions spécifiques ont été expliquées ci-dessus.
Toutes les annotations auront une section similaire à "Func". Cela peut être compris comme un paramètre d'annotation.
Package com.joyfulmath.jvmexample.annnotaion; import com.joyfulmath.jvmexample.tracelog; / *** @author Deman.lu * @version sur 2016-05-23 13: 37 * / public class Apple {@FruitName ("Apple") String Applename; Public Vendi Le journal de ce code:
05-23 13: 39: 38.780 26792-26792 / com.joyfulmath.jvmexample i / Apple: DisplayApplename: null [at (Apple.java:16)]
Pourquoi la mission ne réussit-elle pas? Comment attribuer le fichier à l'annotation "Apple"? Comment le faire si le compilateur ne sait pas encore.
3. Processeur d'annotation
Nous avons également besoin d'un processeur pour expliquer comment les annotations fonctionnent, sinon ce sera presque le même que les annotations.
Grâce à la réflexion, le contenu d'annotation peut être obtenu:
Package com.joyfulmath.jvmexample.annnotaion; import com.joyfulmath.jvmexample.tracelog; import java.lang.reflect.field; / *** @author deman.lu * @version sur 2016-05-23 14: 08 * / classe publique FruitInfouls {STRACK STATIC OVOID GetFruitfo (CLASS <? FruitNameStr = ""; champ [] champs = Clazz.getDeclaredFields (); pour (champ de champ: champs) {if (field.isannotationPresent (fruckename.class)) {fruitName FruitName = Field.getAnnotation (fruitName.class); fruitnamestr = fruitName.Value (); TraceLog.i (fructuckerm);C'est l'utilisation générale des annotations.
Analyse du cadre d'annotation Android
Comme on peut le voir à partir de ce qui précède, l'utilisation de cadres d'annotation nécessite essentiellement une réflexion.
Mais si j'utilise le cadre d'annotation avec la fonction de réflexion, je pourrais aussi bien l'utiliser directement, c'est plus simple.
S'il y a un mécanisme, cela peut éviter d'écrire beaucoup de code similaire en double, en particulier pendant le développement Android, un grand nombre de FindViewbyid & onclick et d'autres événements correspondent.
Le modèle de code est cohérent, mais le code est différent. Pour le moment, l'utilisation du cadre d'annotation peut économiser beaucoup de temps de développement, et bien sûr, il augmentera les autres frais généraux en conséquence.
Voici un exemple d'utilisation de Butter Knife:
@Bindstring (r.string.login_error)
String LoginerrorMessage;
Cela semble très simple, il s'agit d'attribuer une chaîne à la valeur initiale correspondant à String Res. De cette façon, vous pouvez gagner du temps. Bien sûr, ce n'est qu'un exemple.
Si vous utilisez fortement d'autres annotations, vous pouvez économiser beaucoup de temps de développement.
Voyons comment il est mis en œuvre:
Package Butterknife; import Android.Support.annotation.stringres; import java.lang.annotation.retention; importer java.lang.annotation.field; importer static java.lang.annotation.elementtype.field <pre> <code> * {@literal @} bindString (r.string.username_error) String usernameerrorText; * </code> </ pre> * / @ retention (class) @target (champ) public @interface bindstring {/ ** string Resource id id le champ sera lié. * / @ StringRes int Value ();} BindString n'a qu'un seul paramètre, valeur, c'est-à-dire en attribuant la valeur à @stringres.
Identique à ci-dessus, ce qui précède est l'endroit où l'annotation est définie et utilisée, mais l'explication réelle de l'annotation est la suivante:
Map privé <ypeElement, BindingClass> findAndParsetargets (roundirvironment env)
Cette fonction intercepte un code:
// traite chaque @bindstring element.for (élément élément: Env.getElementsAnnotedWith (bindString.class)) {if (! SuperficialValidation.ValidateElement (élément)) Continuer; Try {PARSERESORCESTRING (élément, cibleClassmap, ElasseDtargetNames);} Catch (exception e) {logAtSingher e);}} Trouvez tous les éléments des annotations de Bindstring et commencez à analyser:
private void parsereSourcestring (élément élément, map <ypeElement, bindingClass> targetclassmap, set <ypeElement> eleasedTargetNames) {boolean haserror = false; typeelement EnternerElement = (typeElement) element.getCllAsElement (); // Vérifier que le type cible est string.if (! String_type.equals (element.astype (). ToString ())) {error (élément, "@% s Le type de champ doit être 'string'. (% S.% S)", bindstring.class.getSimplename (), enclosingElement.getQualifiedName (), élément.getsimpléName ()); hasérror = true;} / vife généré de génération ()); hasérror = true; restrictions.haserror | = isInAccessibleViageneRedCode (bindstring.class, "fields", élément); Haserror | = isBindingInwrongPackage (bindstring.class, élément); if (Haserror) {return;} // assemble information sur le champ. element.getAntoTation (bindString.class) .Value (); binkingClass binkingClass = getorcreateTargetClass (TargetClassMap, EnclosingElement); FielDresourceBinding Binding = new FielDresourceBinding (id, nom, "getString",, false); binkingclass.addresource (liant); eleasedtargetNames.add (enclosingElement);} Vérifiez d'abord si l'élément est un type de chaîne.
// Assemblez des informations sur le champ.String name = element.getSimplename (). ToString (); int id = element.getAnTannotation (bindString.class) .value ();
Obtenez le nom du champ et l'ID de chaîne.
final
Map <typeelement, bindingclass> targetclassmap
Les éléments et les descriptions d'annotation sont stockés un par un sur la carte.
@Override Public Boolean Process (set <? ExtendSy TypeElement> Elements, Rountenirvironment Env) {map <typeElement, bindingClass> targetClassMap = findAndParsetargets (env); for (map.entry <ypelementation, bindingclass> entry. entry.getValue (); try {binkingClass.Brewjava (). WriteTo (filer);} catch (ioException e) {error (typeElement, "Impossible d'écrire Binder de la vue pour type% s:% s", typeelement, e.getMessage ());}} return true;} C'est là que le cadre d'annotation est démarré, un processus indépendant. Cet article n'étudie pas les détails spécifiques, il suffit de l'effacer, c'est la place axée sur le cadre.
D'après les informations ci-dessus, toutes les informations d'annotation sont stockées dans TargetClassMap.
Le code marqué rouge ci-dessus devrait être le cœur du cadre d'annotation.
Depuis Java SE5, Java a introduit l'outil APT, qui peut prétraiter les annotations. Java SE6 prend en charge le processeur d'annotation étendue.
Et le traiter plusieurs fois pendant la compilation. Nous pouvons utiliser un processeur d'annotation personnalisé pour générer un nouveau code Java en fonction des règles lorsque Java est compilé .
JavaFile Brewjava () {TypeSpec.Builder result = TypeSpec.classBuilder (généréClassName) .AddModificaires (public); if (isFinal) {result.addModifiers (modificateur.Final);} else {result.addTypevariable (typevariabbleName.get ("t", cibleTyPename));} typEname TargetType = isFinal? TargetTypeName: typevariablename.get ("t"); if (hasparentbinding ()) {result.superclass (ParametepezedyPename.get (parentBinding.GeneratedClassName, TargetType));} else {result.addsuperInterface (paramétriedTypeName.get (View_Binder, TargetType));} Result.addMethod (CreatebindMethod (TargetType); if (isGeneratingUnbinder ()) {result.addtype (CreateUnBinderClass (TargetType));} else if (! isfinal) {result.addMethod (createBindTotargetMethod ());} return javafile.builder (générationclassname.packageName (), résultat.build (). Code de Butter Knife. La clé de ce passage est de créer un nouveau fichier.
Écrivez ensuite le contenu pertinent.