Entrevistador: ¿Hablar de anotaciones?

Comprender las anotaciones de Java

La anotación es una parte muy importante de java, la usamos todo el tiempo, especialmente cuando usamos el framework Spring para desarrollar, usaremos muchas anotaciones extrañas en el proyecto (@DataScope, @Log, @Override, etc.) Muchas veces solo usamos estas anotaciones, pero no sabemos mucho acerca de la lógica y los principios de funcionamiento detrás de las anotaciones, y mucho menos desarrollamos una anotación nosotros mismos. Así que hoy registraré mi comprensión de las anotaciones y cómo personalizar una anotación aquí para comunicarme con usted.

En primer lugar, la anotación es un concepto introducido en Java 1.5 y pertenece a un tipo. Las anotaciones proporcionan una serie de datos para modificar el código del programa (clases, métodos, campos), pero la anotación no forma parte del código modificado, es decir, no tiene impacto directo en el funcionamiento del código, y el compilador decide cuál operaciones a realizar

En segundo lugar, Annatation (anotación) es una interfaz, puede obtener el objeto Annatation del elemento en el programa especificado a través de la reflexión y luego obtener la información de metadatos en la anotación a través del objeto

Comience con @Override

Presumiblemente, @Override es el más familiar para nosotros en la codificación habitual. Sabiendo que realmente se usa para la reescritura de métodos, y la subclase anula las anotaciones usadas por el método de la clase principal. Pero cómo logra esta función, hagamos clic en el código fuente para echar un vistazo.

import java.lang.annotation.*;
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

Puede ver que el código fuente es muy corto, no es más que importar un paquete jar, luego usar las otras dos anotaciones y luego usar @interface para declarar esta anotación.

Al hacer clic en @Target y @Retention, encontraremos que siempre están locos entre las tres anotaciones @Documented, @Retention y @Target. De hecho, estas tres anotaciones son meta-anotaciones en las anotaciones.

Meta anotación

Echemos un vistazo a estas tres meta-anotaciones por separado.

@Retención (ciclo de vida)

Indica cómo almacenar las anotaciones marcadas (especificar el nivel de almacenamiento), el entendimiento popular es el ciclo de vida

  • FUENTE: nivel de código fuente, las anotaciones serán descartadas por el compilador y no se guardarán en el archivo de clase compilado
  • CLASE: nivel de archivo de clase (nivel predeterminado), las anotaciones están disponibles en el archivo de clase, pero la JVM las descartará y no se cargarán en la máquina virtual durante la ejecución.
  • RUNTIME: nivel de tiempo de ejecución, que también se reservará durante el tiempo de ejecución (JVM), por lo que el contenido de la anotación se puede leer a través del mecanismo de reflexión. Como @Controller, @Autowired, @RequestMapping, etc. en SpringMvc.

@Objetivo

Indica que la anotación marcada se puede utilizar para el tipo de elemento java (clase, interfaz, atributo, método). Hay ocho tipos en total.

Entre ellos, ElementType es un tipo enumerado, que se define de la siguiente manera: indica el posible rango de valores

public enum ElementType{
     // 标明该注解可以用于类、接口(包括注解类型)或enum声明
    TYPE,

    // 标明该注解可以用于字段(域)声明,包括enum实例 
    FIELD,

    // 标明该注解可以用于方法声明 
    METHOD,

    // 标明该注解可以用于参数声明 
    PARAMETER,

    // 标明注解可以用于构造函数声明 
    CONSTRUCTOR,

    // 标明注解可以用于局部变量声明 
    LOCAL_VARIABLE,

    // 标明注解可以用于注解声明(应用于另一个注解上)
    ANNOTATION_TYPE,

    // 标明注解可以用于包声明 
    PACKAGE,

    //标明注解可以用于类型参数声明(1.8新加入)
    TYPE_PARAMETER,

    // 类型使用声明(1.8新加入)
    TYPE_USE
}

Cuando la anotación es un valor de destino especificado, esta anotación se puede utilizar en cualquier elemento y varios valores se incluyen con {} y se separan por comas.

@Documentado

Siempre que use las anotaciones especificadas, debe usar la herramienta Javadoc para registrar estos elementos. (Es decir, se agregarán comentarios al javadoc generado)

@Heredado

El tipo de anotación se puede heredar de la superclase, que solo se usa para la declaración de la clase (la interfaz no heredará)

@Repetible

Introducida en Java SE 8, la anotación que representa la marca se puede aplicar a la misma declaración o uso de tipo varias veces.

Clasificación de anotaciones

A través de la comprensión de las meta-anotaciones, entiendo que una anotación es modificada por estas meta-anotaciones, y también hemos ganado un mensaje importante: las anotaciones pueden modificar las anotaciones.

Una matrioska tan infinita tendrá varias anotaciones, entonces, ¿qué anotaciones hay? Las anotaciones comunes se dividen aproximadamente en las siguientes cuatro categorías:

  • Meta-anotación: un tipo tiene cinco tipos
  • anotación jdk: los más comunes son nuestro @Override, @Deprecated: usado para indicar métodos o clases desactualizados, etc.
  • Anotaciones de terceros: son las anotaciones del marco de terceros Spring, etc.con las que estamos familiarizados, @Autowired, etc.
  • Anotaciones personalizadas: las anotaciones personalizadas por los desarrolladores de acuerdo con los requisitos del proyecto se utilizan para el análisis y uso de algunas herramientas durante la compilación y el tiempo de ejecución, y desempeñan el papel de explicación y configuración. Al final del artículo, escribiremos un anotación.

Procesador de anotaciones

Una parte importante del proceso de uso de anotaciones es crear un procesador de anotaciones.

  • Ejemplo:

    • Anotación de definición:
import java.lang.annotation.*;

@Target(ElementType.FIELD)
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface FruitProvider{
    public int id() default -1;
    public String name() default "";
    public String address() default "";
}
    • Uso de anotaciones:
public class Apple {
    @FruitProvider(id=1,name="zhonghu",address = "china")
    private String appleProvider;

    public String getAppleProvider() {
        return appleProvider;
    }

    public void setAppleProvider(String appleProvider) {
        this.appleProvider = appleProvider;
    }
}
    • Procesador de anotaciones:
import java.lang.reflect.Field;


public class FruitInfoUtil {
    public static void getFruitInfo(Class<?> clazz){
        String strFruitProvicer = "供应商信息:";
        Field[] fields = clazz.getDeclaredFields();//通过反射获取处理注解
        for (Field field : fields) {
            if (field.isAnnotationPresent(FruitProvider.class)) {
                FruitProvider fruitProvider = (FruitProvider) field.getAnnotation(FruitProvider.class);
                //注解信息的处理地方
                strFruitProvicer = " 供应商编号:" + fruitProvider.id() + " 供应商名称:"
                        + fruitProvider.name() + " 供应商地址:"+ fruitProvider.address();
                System.out.println(strFruitProvicer);
            }
        }
    }
}
    • Producción
public class FruitRun {
    public static void main(String[] args) {
        FruitInfoUtil.getFruitInfo(Apple.class);
    }
}
  • resultado:
    imagen

El papel de las anotaciones

  • El formato se comprueba en el momento de la compilación. Tal como@Override
  • Seguimiento de las dependencias del código y realización de la función de sustitución de archivos de configuración. Genere código y archivos XML procesando información de anotaciones.
  • Algunos comentarios se pueden comprobar en tiempo de ejecución

Empieza a comentar

Antes de que comience el combate real, también debemos comprender las reglas para escribir anotaciones personalizadas

regla

  • La definición de anotación es @interfaceque todas las anotaciones heredarán automáticamente java.lang.Annotationesta interfaz y ya no pueden heredar otras clases o interfaces.

La anotación no admite la herencia

  • Los miembros del parámetro solo se pueden modificar con caracteres de autoridad de acceso publico con ellosdefault(默认)
  • Ocho miembro de parámetro sólo con los tipos de datos básicos, String, Enum, Class, annotationsy otros tipos de datos, y estos tipos de matrices

No se permite ningún tipo de empaque, las anotaciones también se pueden usar como tipos de elementos, es decir, anotaciones anidadas

  • Para obtener la información de anotación de los métodos y campos de la clase, debe obtenerse a través del mecanismo de reflexión de Java

Al mismo tiempo, para obtener con precisión la información relevante de las anotaciones en tiempo de ejecución, java ha agregado la interfaz AnnotatedElement bajo el paquete de reflexión de java.lang.reflect, que se utiliza para indicar los elementos que se han anotado en el programa actualmente. que se ejecutan en la JVM y se proporcionan a través de esta interfaz. El método puede utilizar tecnología de reflexión para leer la información anotada.

  • La anotación tampoco puede tener miembros definidos (solo para identificación)

Escribe anotaciones

Anteriormente, presentamos el uso de anotaciones y la información de las anotaciones. A continuación, marquemos un campo de anotaciones para marcar si el objeto debe incluir este campo cuando se serializa en JSON.

@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.FIELD)
public @interface JsonField {
    public String value() default "";
}
  • Explicación:

    • El ciclo de vida de la anotación JsonField es RUNTIME, que es válido en tiempo de ejecución
    • El objetivo de la modificación de la anotación de JsonField es FIELD, que es para el campo
    • Se necesita la palabra clave @interface para crear una anotación
    • La anotación JsonField tiene solo un parámetro, el nombre es valor, el tipo es Cadena y el valor predeterminado es una cadena vacía

El nombre del parámetro es valor, lo que permite al usuario de la anotación proporcionar un parámetro sin especificar un nombre. Es decir, podemos usar @JsonField (value = "塚 狐") en un campo, u omitir value = y convertirnos en @JsonField ("塚 狐")

    • default "" nos permite usar @JsonField directamente en un campo sin especificar el nombre y el valor del parámetro

Usar anotaciones

Cree una clase, que contenga tres campos: edad, nombre, dirección, los dos últimos son necesarios para serializar el campo

public class People {
    private  int age ;

    @JsonField("writeName")
    private String name;

    @JsonField
    private String address;

    public People(int age,String name,String address){
        this.age=age;
        this.name=name;
        this.address=address;
    }

    @Override
    public String toString() {
        return "People{" +
                "age=" + age +
                ", name='" + name + '\'' +
                ", address='" + address + '\'' +
                '}';
    }
}

entre ellos:

  • La anotación @JsonField en el nombre proporciona el valor de cadena mostrado
  • La anotación @JsonField en la dirección usa el valor predeterminado

A continuación escribimos la clase de serialización JsonSerializer:

public class JsonSerializer {
    public static String serialize(Object object) throws IllegalAccessException {
        Class<?> objectClass = object.getClass();
        Map<String, String> jsonElements = new HashMap<>();
        for (Field field : objectClass.getDeclaredFields()) {
            field.setAccessible(true);
            if (field.isAnnotationPresent(JsonField.class)) {
                jsonElements.put(getSerializedKey(field), (String) field.get(object));
            }
        }
        return toJsonString(jsonElements);
    }

    private static String getSerializedKey(Field field) {
        String annotationValue = field.getAnnotation(JsonField.class).value();
        if (annotationValue.isEmpty()) {
            return field.getName();
        } else {
            return annotationValue;
        }
    }

    private static String toJsonString(Map<String, String> jsonMap) {
        String elementsString = jsonMap.entrySet()
                .stream()
                .map(entry -> "\"" + entry.getKey() + "\":\"" + entry.getValue() + "\"")
                .collect(Collectors.joining(","));
        return "{" + elementsString + "}";
    }
}

Echemos un vistazo a sus respectivos significados y funciones:

  • serialize()El método se utiliza para serializar un objeto y recibe un parámetro de tipo Object. objectClass.getDeclaredFields()Obtenga todos los campos declarados por el objeto por reflexión y luego realice un recorrido de bucle for. En un bucle for, primero por field.setAccessible(true)la accesibilidad del objeto reflectante establecida en verdadero, para la secuencia de uso (sin este paso, entonces, el campo privado no se puede obtener, arroja la excepción IllegalAccessException); nuevamente isAnnotationPresent()determinando si el campo decorado JsonFieldanotación, y entonces, llama al getSerializedKey()método, y así obtiene el valor del campo que indica el objeto, y se coloca en jsonElements.
  • getSerializedKey() El método se utiliza para obtener el valor de la anotación en el campo. Si el valor de la anotación está vacío, se devuelve el nombre del campo.
  • toJsonString() El método devuelve la cadena JSON formateada mediante Stream.

Notas de prueba

public class JsonFileTest {
    public static void main(String[] args) throws IllegalAccessException{
        People cmower = new People(18,"冢狐","中国");
        System.out.println(JsonSerializer.serialize(cmower));
    }
}

  • resultado:

{"WriteName": "Mound Fox", "address": "China"}

  • análisis

    • Primero, el campo de edad no está anotado por @JsonField, por lo que no está serializado
    • El nombre modifica la anotación @JsonField y muestra que se especifica la cadena WriterName, por lo que se convierte en writeName después de la serialización.
    • El campo de dirección está decorado con la anotación @JsonField, pero el valor especificado no se muestra, por lo que sigue siendo la dirección después de la serialización

Por fin

  • Si siente que ha sido recompensado después de leerlo, espero que me apruebe. Esta será la mayor motivación para actualizar. Gracias por su apoyo.
  • Bienvenidos a todos para que presten atención a mi cuenta pública [Java Fox], enfocándome en los conocimientos básicos de Java y la computadora, prometo dejarles obtener algo después de leerlo, si no me creen, péguenme
  • Si tiene diferentes opiniones o sugerencias después de leer, por favor comente y comparta con nosotros. Gracias por su apoyo y cariño.

——Soy Chuhu, y amo la programación tanto como a ti.

imagen

Supongo que te gusta

Origin blog.csdn.net/issunmingzhi/article/details/112000502
Recomendado
Clasificación