A menudo vemos cosas como "@Override", "@Target", etc. en el código Java. ¿Qué son éstos?
En Java son "anotaciones".
La siguiente es la explicación de la enciclopedia de Baidu: java.lang.annotation.etention puede instruir al compilador para tratar su anotación personalizada cuando defina el patrón de anotación. El compilador dejará información de anotación en el archivo de clase, pero la máquina virtual no lee, pero solo proporcionará información cuando se ejecuta el compilador o programa de herramientas.
En otras palabras, las anotaciones se basan en archivos de clase y tienen el mismo efecto que las macros en el idioma C.
No hay rastro de anotación en el archivo de clase.
La base de la anotación es la reflexión. Por lo tanto, la anotación puede entenderse como un concepto exclusivo de Java.
1. Meta nota
En el paquete Java.lang.annotation, se han definido cuatro "primitivas" de anotación.
1).@Objetivo, utilizado para aclarar el tipo que se modifica: (métodos, campos, clases, interfaces, etc.)
2).@Retención, describe la existencia de anación:
La anotación RetententPolicy.Runtime existirá en el archivo de Bytecode de clase y se puede obtener a través de la reflexión en tiempo de ejecución.
RetentionPolicy.Class La política de retención predeterminada, la anotación existirá en el archivo de Bytecode de clase, pero no se puede obtener durante el tiempo de ejecución.
La anotación RetententPolicy.
3).@Documentado, por defecto, las anotaciones no se registrarán en Javadoc, pero esta anotación se puede usar para indicar que esta anotación debe registrarse.
4). @La metaanotación heredada es una anotación de etiqueta, y @inherited explica que se hereda un cierto tipo anotado.
Si se usa un tipo de anotación que usa la modificación @inherited para una clase, la anotación se utilizará para una subclase de la clase.
2. Anotaciones personalizadas
paquete com.joyfulmath.jvmexample.annnotaion; import java.lang.annotation.elementType; import java.lang.annotation.retents; import java.lang.annotation.retententPolicy; import java.lang.annotation.target;/*** @author Deman.LU* @version en 2016-2223 13:36*/@Target (elementType.field) @Retention (retentionPolicy.Runtime) public @Interface FruitName {String Value () predeterminado ";} En primer lugar, una anotación generalmente requiere 2 modificaciones de meta anotación:
@Target (elementType.field)
@Retention (retenciónPolicy.Runtime)
Las funciones específicas se han explicado anteriormente.
Todas las anotaciones tendrán una sección similar a "FUNC". Esto puede entenderse como un parámetro de anotación.
paquete com.joyfulmath.jvmexample.annnotaion; import com.joyfulmath.jvmexample.tracelog;/*** @author deman.lu*@version en 2016-05-23 13: 37*/public class Apple {@FruitName ("Apple") String Applename; El registro de este código:
05-23 13: 39: 38.780 26792-26792/com.joyfulmath.jvmexample I/Apple: DisplayAppLename: Null [en (Apple.java:16)]]
¿Por qué la tarea no tiene éxito? ¿Cómo asignar el archivo a la anotación "Apple"? Cómo hacerlo si el compilador aún no lo sabe.
3. Procesador de anotación
También necesitamos un procesador para explicar cómo funcionan las anotaciones, de lo contrario será casi lo mismo que las anotaciones.
A través de la reflexión, se puede obtener el contenido de anotación:
paquete com.joyfulmath.jvmexample.annnotaion; import com.joyfulmath.jvmexample.tracelog; import java.lang.reflect.field;/*** @author deman.lu*@version on 2016-05-23 14: 08*/public ""; Field [] fields = clazz.getDeClaredFields (); for (campo campo: campos) {if (field.isannotationPresent (fruitname.class)) {frutsname frutsname = field.getAnnotation (fruitname.class); frutnamestr = frutitName.value ();Este es el uso general de las anotaciones.
Análisis de marco de anotación de Android
Como se puede ver de lo anterior, el uso de marcos de anotación esencialmente requiere reflexión.
Pero si uso el marco de anotación con la función de la reflexión, entonces podría usarlo directamente, es más simple.
Si hay un mecanismo, puede evitar escribir mucho código similar, especialmente durante el desarrollo de Android, son correspondientes una gran cantidad de FindViewByid & OnClick y otros eventos.
El patrón de código es consistente, pero el código es diferente. En este momento, usar el marco de anotación puede ahorrar mucho tiempo de desarrollo y, por supuesto, aumentará otras sobrecargas en consecuencia.
Aquí hay un ejemplo del uso de Butterknife:
@BindString (r.string.login_error)
String LoginerrormeSage;
Parece muy simple, es asignar una cadena al valor inicial correspondiente a String Res. De esta manera puedes ahorrar algo de tiempo. Por supuesto, esto es solo un ejemplo.
Si usa otras anotaciones en gran medida, puede ahorrar mucho tiempo de desarrollo.
Veamos cómo se implementa:
paquete de mantequilla; import android.support.annotation.stringres; import java.lang.annotation.retention; import java.lang.annotation.target; import static java.lang.annotation.elementType.field; import static java.lang.annotation.raticpolicy.class;/*** bind Bind a Field a The Speced.* <pre> <code>* {@literal @} bindString (r.string.username_error) String usernameErrortext;* </code> </pre>*/ @retención (class) @Target (campo) public @interface BindSting {/** ID de recurso de cadena a la cual el campo estará vinculado. */@Stringres int value ();} BindString tiene solo un parámetro, valor, es decir, asignar el valor a @StringRes.
Igual que el anterior, lo anterior es donde se define y usa la anotación, pero la verdadera explicación de la anotación es la siguiente: Butterknifeprocessor
Mapa privado <TypeElement, BindingClass> FindAndParsetArgets (redonvironment Env)
Esta función intercepta algún código:
// procesa cada uno @bindstring elemento e);}}
Encuentre todos los elementos de las anotaciones de BindString y comience a analizar:
privado void parseresourCestring (elemento elemento, map <tiposelement, bindingclass> targetClassMap, set <ipeElement> ERASEDTARGETNAMES) {boolean hasError = false; typeElement enclosingElement = (typeElement) element.getencLosingElement (); // Verifique que el tipo de destino sea cadena. (. restricciones.haserror | = isInAnAccessibleViaGeneratedCode (bindString.class, "Fields", Element); HasError | = isBindingInwrongPackage (bindString.class, elemento); if (HasErRor) {return;} // ensamblar información en el campo. element.getAnnotation (BindString.Class) .Value (); BindingClass BindingClass = GetOrCreateTargetClass (TargetClassMap, ClosingElement); FieldResourceBinding Binding = New FieldResourceBinding (id, nombre ", Getting",,,,,,,,, getting ",,,",, ",", ",",, ",", ",",, ",", ",", ",",, ",", ",",, ",", ",,", ",", ",", ",",, ",", ",", ",", ",,", ",", ",", ",", ",", ", Getting",,,, ", falso); bindingclass.addresource (vinculante); borradoTargetNames.Add (enclosingElement);} Primero verifique si el elemento es un tipo de cadena.
// ensamble la información en el nombre.string name = element.getSimplename (). ToString (); int id = element.getAnnotation (bindString.Class) .Value ();
Obtenga el nombre del campo y la ID de cadena.
final
MAP <TypeElement, BindingClass> TargetClassMap
Los elementos y las descripciones de anotación se almacenan una por una en el mapa.
@Override Public Boolean Process (SET <? Extends TypeElement> Elements, RoundEnvironment Env) {map <typeElement, bindingClass> targetClassMap = findandParsetArgets (env); for (map.Entry <typeElement, bindingClass> Entry: targetClassMap.Entryset ()) {typeelement typeelement = entry.getkey (); bykingClass = entry.getValue (); try {bindingClass.BrewJava (). WriteTo (FileR);} Catch (ioException e) {error (TypeElement, "No se puede escribir un aglutinante de vista para el tipo %s: %s", typeElement, e.getMessage ());}} return real;} Aquí es donde se inicia el marco de anotación, un proceso independiente. Este artículo no estudiará los detalles específicos, solo claro, este es el lugar impulsado por el marco.
De la información anterior, toda la información de anotación se almacena en el TargetClassMap.
El código marcado de rojo arriba debe ser el núcleo del marco de anotación.
Desde Java SE5, Java ha introducido la herramienta APT, que puede preprocesar anotaciones. Java SE6 admite procesador de anotación extendida.
Y procesar varias veces durante la compilación. Podemos usar un procesador de anotación personalizado para generar un nuevo código Java de acuerdo con las reglas cuando se compila Java .
Javafile brewJava () {typespec.builder result = typespec.classBuilder (generadoclassname) .addmodifiers (public); if (isFinal) {result.AddModifiers (modificador.final);} else {result.AddTypeVariable (wypeVariablename.get ("t", targettypename));} typename targetType = isFinal? Targettypename: wypevariablename.get ("t"); if (hasParentBinding ()) {result.superClass (parameterizedTypename.get (parentBinding.GeneratedClassName, TargetType));} else {result.addsuperterface (parameterizedTypename.get (ver_binder, targetType));} result.addmethod (createbindmethod (targetType); if (isGeneratingUnBinder ()) {resultado.AddType (createUnBinderClass (TargetType));} else if (! IsFinal) {result.AddMethod (createBindToTargetMethod ());} return javafile.buDerIder (generado de generado Cuchillo de mantequilla. La clave de este pasaje es crear un nuevo archivo.
Luego escriba el contenido relevante.