Peinado de puntos de conocimiento: notas Java

Anotaciones Java

Prólogo

Recientemente, he estado clasificando algunos de los conocimientos que he aprendido, ¡con la intención de registrarlos bien, perfeccionando mi sistema de conocimiento personal y apegándome a ellos! Corriendo


porque aprender

Spring, Mybatis, lombok, etc. Hemos desarrollado muchos marcos al desarrollar programas. La mayoría de ellos proporcionan sus propias notas de implementación. El uso experto puede ayudarme a completar mi programa, pero ¿cómo lo hizo? ¿Cómo una pequeña anotación logra una función tan poderosa? Decidí estudiar el mecanismo de anotación de Java cuidadosamente al pensar en este problema.

¿Qué es la anotación?

Las anotaciones fueron introducidas por JDK5 y son el soporte de Java para metadatos. En lenguaje humano, es una marca especial en el código. Estas marcas se pueden leer y ejecutar en algún momento, para que los desarrolladores puedan mejorar nuestro programa sin cambiar la lógica del código comercial original.


Primer vistazo a algunas anotaciones básicas proporcionadas por Java

  • @Anular
  • @Obsoleto
  • @SupressWarning

Las anotaciones anteriores a menudo aparecen en varios códigos fuente. Para ser honesto, antes de anotar el conocimiento del lado del sistema, siempre miro las anotaciones. ¿Qué escribo y no entiendo? ? ? ?

Después de leer algunos libros y ordenarlos, de repente se vuelve brillante

Déjame escuchar despacio

@Anular

⚠️ Nota: esta anotación solo se puede usar en métodos (¿por qué dice a continuación?)

Esta anotación es muy común. Cada vez que reescribe el método principal o implementa el método de interfaz, la herramienta de desarrollo inteligente me agregará automáticamente dicha anotación. Al principio, la rechacé. Más tarde me enteré de que esta anotación se agrega Para ayudar a los desarrolladores a verificar si la implementación del método de la clase principal es correcta.

Para un castaño, si hay un método llamado hola en la clase principal, entonces la subclase que lo hereda puede reescribirse, en caso de que se lo haya perdido y lo haya escrito como helo, aunque no está reescrito correctamente, no está mal, porque Puede verse como un nuevo método de la subclase, en este momento el programa se puede ejecutar correctamente. Pero si la anotación @Override se agrega al método helo, entonces el compilador sabe que este método es una subclase para reescribir el método de la clase principal, verificará automáticamente si el método de la clase principal se reescribe correctamente (obviamente, el padre La clase no tiene método helo, necesitamos reescribir hello (), luego compilará el error)

Un conjunto de palabras, una oración es que @Override es para ayudar a los desarrolladores a verificar si el método reescrito es correcto (verifique el valor de retorno del parámetro del nombre del método, etc.)

@Obsoleto

⚠️ Nota: esta anotación se puede usar en clases y métodos

El significado de este comentario es muy simple, se usa para marcar código obsoleto

public class TestAnnotation {

	public static void main(String[] args) {
		new DeprecatedClass().info();
	}
	
}

// 下面定义了一个类,加了@Deprecated表示他是过时的
// 类中有一个方法,也是过时的 23333


@Deprecated
class DeprecatedClass {
	
	@Deprecated
	public void info() {
		System.out.println("giao");
	}
	
}
复制代码

Si compila este programa, se le advertirá que esta clase y este método están desactualizados, pero no afecta la ejecución del programa.

@SuppressWarnings

Esta anotación puede ayudar a eliminar advertencias en tiempo de compilación

Como una castaña, hay un método sayHello () en mi programa. Este método devuelve una Cadena. Cuando llamo a este método, simplemente llamo pero ignoro el valor de retorno de usar este método. Luego, cuando compilo este programa, simplemente Habrá una advertencia de que ignoro el valor de retorno. En este momento, puedo agregar @SuppressWarnings ("sin usar") al método. Sin usar significa advertencia sin usar. Este uso le indicará al compilador que ignore esta advertencia. Esta advertencia ya no se emitirá.

public class TestAnnotation {

	public static void main(String[] args) {
		// 如果我不加这个注解就会有警告,but你可以不理他,警告并不会对程序运行有影响
		@SuppressWarnings("unused")
		String string = new SuppressWarningClass().sayHello();
	}

}

class SuppressWarningClass {
	
	public String sayHello() {
		return "hello";
	}
	
}
复制代码

Las tres anotaciones anteriores son algunas anotaciones básicas proporcionadas por Java (por supuesto, más que eso). Los ejemplos son solo para ayudarnos a comprender rápidamente las anotaciones. Pruebe las anotaciones rápidamente. Leamos en profundidad para comprenderlas. El secreto detras


Meta Anotación proporcionada por Java

La definición de una anotación debe ser la anotación meta. Java viene con varias anotaciones meta para ayudar a modificar la definición de otras anotaciones.

@Retencion

Esta anotación solo se puede modificar a otras anotaciones. Se usa para especificar el tiempo de retención de la anotación modificada. @ La anotación de retención contiene un valor de variable miembro de tipo RetentionPolicy. Establecemos el tiempo de retención especificando el valor del valor (el método especificado es en realidad Es @Retention (value = RetentionPolicy.RUNTIME), que se especifica pasando el nombre de la variable miembro correspondiente = valor entre paréntesis)

Para el tiempo de retención de las anotaciones, el valor de @Retention solo se puede establecer por tres

  1. RetentionPolicy.SOURCE: la anotación modificada solo puede estar en el código fuente y el compilador la ignorará directamente
  2. RetentionPolicy.CLASS: la anotación modificada se puede almacenar en el archivo de clase compilado, pero no se puede obtener en tiempo de ejecución
  3. RetentionPolicy.RUNTIME: la anotación modificada puede existir en el archivo de clase y la información de la anotación se puede obtener mediante reflexión durante la operación
@Retention(RUNTIME) // 设置其可存活的时间
public @interface MyAnnotation {

}
复制代码

por cierto, si solo necesita asignar un valor a una variable miembro denominada valor en la anotación, puede especificarlo sin nombre = valor y simplemente escribirlo. En el cuadro anterior, @Retention (RUNTIME) usa este método para asignar directamente valores a valores

@Objetivo

Esta anotación también se usa para modificar la anotación. Se usa para especificar que la anotación modificada solo se puede usar en la unidad del programa. Por ejemplo, la anotación @Override introducida anteriormente se debe a que la especificación @Target solo se puede modificar en el método.

@Target tiene muchos valores, tiene una enumeración de ElementType:

  1. Clase o interfaz: ElementType.TYPE;
  2. Campo: ElementType.FIELD;
  3. Método: ElementType.METHOD;
  4. Método de construcción: ElementType.CONSTRUCTOR;
  5. Parámetros del método: ElementType.PARAMETER
  6. Solo se puede usar para modificar anotaciones: ElementType.ANNOTATION_TYPE
  7. Variable local: ElementType.LOCAL_VARIABLE
  8. Definición del paquete: ElementType.PACKAGE

El código fuente de @ Target es así

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}
复制代码

Se define como una anotación que solo se puede modificar, tiene un valor de variable miembro, por lo que podemos definir directamente el valor entre paréntesis, como dije anteriormente, no es necesario agregar valor =, puede notar que el tipo de valor aquí ElementType [], esta es una matriz, entonces significa que si necesitamos definir múltiples, podemos especificarla directamente en forma de matriz, como la siguiente

@Target({CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
复制代码

@Documento

Esta anotación tiene menos efecto que las dos anteriores, y se puede ver que su nombre está relacionado con el documento

Las anotaciones modificadas por esta anotación se pueden ver en la documentación generada por javadoc, nada más ...

@Heredado

Las anotaciones modificadas por esta anotación tendrán herencia. Por ejemplo, hay una anotación X modificada por @Inherited. Si la anotación X se agrega a la clase A, todas sus subclases se anotarán automáticamente con X Puedes verlo mirando el código compilado ~)


Anotación personalizada

Hay mucha ropa de cama, intentemos definir anotaciones por nosotros mismos

Anotación de definición

La definición de una anotación es similar a la definición de una interfaz. La palabra clave de la interfaz es interfac, y la palabra clave de la anotación es @interface (es decir, agregue una @ en función de la interfaz)

public @interface MyAnnotation {

}
复制代码

Usar esta anotación también es muy simple, solo agréguela directamente a la cabeza que desea usar

@MyAnnotation
class TestMyAnnotation {
	
	@MyAnnotation
	public void testMethod() {
		
	}
	
}
复制代码

Las anotaciones pueden tener sus propias variables miembro

public @interface MyAnnotation {

	String value();
	
	int age();
	
}
复制代码

Después de definir las variables miembro, se les deben asignar valores cuando se usan

@MyAnnotation(value = "test", age = 123)
class TestMyAnnotation {
	
	@MyAnnotation(value = "abc", age = 234)
	public void testMethod() {
		
	}
	
}
复制代码

Por supuesto, también puede establecer un valor predeterminado para ellos, de modo que no necesite asignar un valor cuando lo use. Cuando no asigna un valor, el valor predeterminado se usa directamente.

Use la palabra clave devalut para establecer el valor predeterminado para su implementación

public @interface MyAnnotation {

	String value() default "abc";
	
	int age() default 123;
	
}
复制代码

Dependiendo de si tiene variables miembro, Anotación se puede dividir en los siguientes dos tipos:

  1. Anotación de marca: anotación de variables sin miembros, solo utilizan su propia existencia para proporcionar información, como @Override, etc., presentada anteriormente
  2. Meta Anotación: hay variables miembro, pueden aceptar más datos, por lo que también se llama Meta Anotación

Extraer información de anotación

Habiendo dicho tantas anotaciones, también presenté cómo personalizar una anotación. La pregunta es, ¿cómo funcionan exactamente estas anotaciones? Seguimos explorando

Extraer datos

Una anotación no tiene efecto solo en virtud de sí misma. Los desarrolladores deben proporcionar las herramientas correspondientes para extraer su información para que funcione.

Definimos una anotación. De hecho, esencialmente implementa la interfaz de anotación proporcionada por Java. La interfaz de anotación es la interfaz principal de todas las anotaciones. Al mismo tiempo, Java5 presenta la interfaz AnnotatedElement, que es la interfaz principal de todos los elementos del programa (como clase, interfaz, método, etc.), por lo que, mediante la reflexión y el uso del método proporcionado por AnnotatedElement, podemos obtener la información en las anotaciones. , Directamente en el código

AnnotatedElement proporciona varios métodos muy útiles para ayudarnos a obtener la información de las anotaciones

  1. getAnnotation (Class) donde Class es el tipo específico que se pasa, como MyAnnotation.class, obtiene anotaciones según el tipo o devuelve Null si no se puede obtener
  2. getDeclaredAnnotation (Class) Este método es el mismo que getAnnotation anterior. La única diferencia es que obtiene las anotaciones directamente modificadas en el método. Recuerde que si las anotaciones que mencionamos anteriormente se heredan (al usar @Inherited), el uso de este método no es Obtendrá anotaciones heredadas
  3. getAnnotations (): esto significa obtener todas las anotaciones en el objeto
  4. getDeclaredAnnotations (): también se usa para obtener todas las anotaciones, la diferencia es la misma que getAnnotation y getDeclaredAnnotation
  5. isAnnotationPresent (Class): Aquí Class es el tipo específico pasado, como MyAnnotation.class, utilizado para determinar si hay anotaciones de este tipo en el elemento objeto, si es verdadero, devuelve verdadero, de lo contrario devuelve falso
  6. getAnnotationsByType (): devuelve la matriz de anotaciones del tipo especificado existente en el elemento del programa (debido a la nueva característica de anotación agregada en Java 8, la diferencia entre este método y las getAnnotations anteriores es que uno obtiene todo de acuerdo con el tipo, uno obtiene todo)
  7. getDeclaredAnnotationsByType (): el significado es similar al anterior getAnnotationsByType, la diferencia es que se obtienen las anotaciones que actúan directamente sobre los elementos (la diferencia es la misma que getAnnotation y getDeclaredAnnotation)
public void getMyAnnotation() throws NoSuchMethodException, SecurityException, ClassNotFoundException {
	Annotation[]  annotations = Class.forName("com.learn.javase.TestMyAnnotation").getMethod("testMethod").getAnnotations();
	for (Annotation annotation : annotations) {
		System.out.println(annotation);
	}
}
复制代码

El código anterior es la forma más fácil de obtener Anotación en el método. Aquí usamos el método getAnnotations proporcionado por AnnotatedElement para obtener todas las anotaciones en este elemento del programa e imprimirlo en un bucle.

Además, si desea obtener el valor de la variable miembro en la anotación también es muy simple

public void getMyAnnotation2() throws NoSuchMethodException, SecurityException, ClassNotFoundException {
	Method[] methods = Class.forName("com.learn.javase.TestMyAnnotation").getMethods();
	for (Method method : methods) {
		MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class);
		// 此处需要做一个判空
		if (myAnnotation != null) {
			System.out.println("value="+myAnnotation.value()+",age="+myAnnotation.age());
		}
	}
}
复制代码

Java8 anotaciones repetidas

De hecho, hay anotaciones repetidas antes de Java8, pero solo a través de una curva. En primer lugar, Java no permite dos comentarios idénticos en un elemento del programa, como el siguiente, la compilación del programa informará directamente un error

@MyAnnotation(value = "test", age = 123)
@MyAnnotation(value = "test", age = 234)
class TestMyAnnotation3 {
	
}
复制代码

Pero esta operación se puede lograr de una manera especial, que es definir un contenedor de anotaciones, como:

@Retention(RUNTIME) // 设置其可存活的时间
public @interface MyAnnotationColloection {

	MyAnnotation[] value();
		
}
复制代码

A través de esta definición, puede lograr anotaciones repetidas en un gesto extraño, como este:

@MyAnnotationColloection({@MyAnnotation(value = "test", age = 123),@MyAnnotation(value = "test", age = 123)})
class TestMyAnnotation3 {
	
}
复制代码

Preste atención a este lugar, el tiempo de almacenamiento del contenedor debe ser mayor o igual que la anotación específica

Sin embargo, esto no es realmente hermoso, por lo que Java8 introdujo la anotación @Repeatable, podemos agregar la anotación @Repeatable para modificar al definir @MyAnnotation, el valor se pasa a la clase contenedor, de esta manera:

@Repeatable(MyAnnotationColloection.class)
@Retention(RUNTIME) // 设置其可存活的时间
public @interface MyAnnotation {

	String value() default "abc";
	
	int age() default 123;
	
}
复制代码

Así que ahora podemos usar anotaciones de repetición más bella

@MyAnnotation(value = "test", age = 123)
@MyAnnotation(value = "test", age = 123)
//@MyAnnotationColloection({@MyAnnotation(value = "test", age = 123),@MyAnnotation(value = "test", age = 123)})
class TestMyAnnotation3 {
	
}
复制代码

Pero para decirlo sin rodeos de esta manera, la esencia sigue siendo la misma que la presentada originalmente. La nueva forma de escribir es solo una simplificación del método anterior, porque todavía se define repetidamente en forma de contenedor


Nueva anotación de tipo en Java 8

En Java8, ElementType agrega dos miembros de enumeración, TYPE_PARAMETER y TYPE_USE. Las anotaciones solo se pueden marcar en una declaración (como campos, clases, métodos) antes de Java8. Después de Java8, el nuevo TYPE_PARAMETER se puede usar para marcar parámetros de tipo TYPE_USE se puede usar para etiquetar cualquier tipo (sin incluir la clase).

Si se define como este rango, la anotación se puede modificar en las siguientes posiciones:

  1. Al crear un objeto (antes de un nuevo objeto)
  2. Cuando tipo de conversión
  3. Al implementar la interfaz
  4. lanza cuando se lanza una excepción
class D<@Parameter T> { }class Image implements @Rectangular Shape { }new @Path String("/usr/bin")
 
 
String path=(@Path String)input;if(input instanceof @Path String)public Person read() throws @Localized IOException.List<@ReadOnly ? extends Person>List<? extends @ReadOnly Person>
 
@NotNull String.class 

import java.lang.@NotNull String
复制代码

APTO

Aquí solo daré una breve introducción sobre este concepto, porque el contacto personal es muy limitado.

APT (Herramienta de procesamiento de anotaciones) es una herramienta de procesamiento de anotaciones que se utiliza para generar código. En otras palabras, es una herramienta para generar código utilizando código. El propósito de usarlo es simplificar la carga de trabajo de los desarrolladores. La definición de procesador de anotación debe heredar una clase padre AbstractProcessor. A través de los métodos proporcionados por ella, podemos obtener la información de esta anotación y realizar la operación que desee por otros medios que no sean la reflexión.

Después de implementar un APT específico, su funcionamiento depende de comandos especiales de javac

javac -processor APT的类名 具体的java文件.java
复制代码

Supongo que te gusta

Origin juejin.im/post/5e9c492fe51d45471263fa18
Recomendado
Clasificación