1 简介
注解:元数据。方便后续使用这些数据。
(1)提供描述程序所需的额外信息。
(2)提高代码易读性和简洁性。
(3)编译期类型检查,可由编译器进行测试和验证注解的正确性,如标准注解@Override、@Deprecated、@SuppressWarngings。
元注解:注解其他注解,修饰自定义的注解,使其按照既定的轨迹运行。
序号 | 元注解 | 描述 |
---|---|---|
1 | @Target | 注解标注的位置,如类、方法、参数等。标识值有10种: (1)TYPE:类、接口(包括注解类型)或者enum (2)FIELD:域 (3)METHOD:方法 (4)PARAMETER:常规参数 (5)CONSTRUCTOR:构造器 (6)LOCAL_VARIABLE:局部变量 (7)ANNOTATION_TYPE:注解类型 (8)PACKAGE:包 (9)TYPE_PARAMETER:类型参数 (10)TYPE_USE:类型检查 |
2 | @Retention | 注解存活的阶段。标识有3种: (1)SOURCE:不使用,直接被编译器丢弃 (2)CLASS:class文件中可用,运行时无法获取,被VM丢弃 (3)RUNTIME:运行时可用,可通过反射获取注解信息 |
3 | @Documented | 注解包含在JavaDoc中 |
4 | @Inherited | 允许子类继承父类中的注解 |
2 类注解
这里讲解类注解类型:ElementType.TYPE
2.1 自定义注解
package com.monkey.java_study.annotation.clazz;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 类注解.
*
* @author xindaqi
* @date 2022-03-17 15:19
*/
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyClassAnnotation {
/**
* id.
*
* @return id
*/
public int id();
/**
* 注解描述.
*
* @return 描述信息
*/
public String description() default "自定义类注解";
}
2.2 注解应用
在不同的类中标注类注解。
- 类1
package com.monkey.java_study.annotation.clazz;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 类注解:应用.
*
* @author xindaqi
* @date 2022-03-17 15:21
*/
@MyClassAnnotation(id = 1)
public class Class1AnnotationUsing {
private static final Logger logger = LoggerFactory.getLogger(Class1AnnotationUsing.class);
public void test() {
logger.info(">>>>>>>>Class 1");
}
}
- 类2
package com.monkey.java_study.annotation.clazz;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 类注解:应用.
*
* @author xindaqi
* @date 2022-03-17 15:22
*/
@MyClassAnnotation(id = 2)
public class Class2AnnotationUsing {
private static final Logger logger = LoggerFactory.getLogger(Class2AnnotationUsing.class);
public void test() {
logger.info(">>>>>>>>Class 1");
}
}
2.3 测试
获取类注解直接通过getAnnotations获取注解数组,一个类可以被多个注解标识。
不同的注解可以自定义不同的处理方式,使用instanceof判断注解类型,做相应处理。
获取注解后,通过类型强转,提取注解的方法,获取对应的值。
package com.monkey.java_study.annotation.clazz;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import sun.reflect.annotation.AnnotationType;
import java.lang.annotation.Annotation;
/**
* 类注解测试.
*
* @author xindaqi
* @date 2022-03-17 15:28
*/
public class ClassAnnotationTest {
private static final Logger logger = LoggerFactory.getLogger(ClassAnnotationTest.class);
private static void processAnnotation(Class<?> clzz) {
Annotation[] annotations = clzz.getAnnotations();
for(Annotation annotation : annotations) {
if(annotation instanceof MyClassAnnotation) {
logger.info(">>>>>>>>MyClassAnnotation id:{},description:{}", ((MyClassAnnotation) annotation).id(), ((MyClassAnnotation) annotation).description());
}
}
}
public static void main(String[] args) {
processAnnotation(Class1AnnotationUsing.class);
processAnnotation(Class2AnnotationUsing.class);
}
}
2.4 测试结果
3 方法级注解
这里讲解方法注解类型:ElementType.METHOD
3.1 自定义注解
package com.monkey.java_study.annotation;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 方法级注解.
*
* @author xindaqi
* @date 2022-03-16 15:44
*/
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
/**
* id
*
* @return id
*/
public int id();
/**
* 描述信息.
*
* @return 描述信息
*/
public String description() default "自定义注解";
}
3.2 注解应用
package com.monkey.java_study.annotation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
/**
* 方法注解测试.
*
* @author xindaqi
* @date 2022-03-17 9:58
*/
public class AnnotationUsing {
private static final Logger logger = LoggerFactory.getLogger(AnnotationUsing.class);
@MyAnnotation(id = 1)
public void myMethod1() {
logger.info(">>>>>>>My method1");
}
@MyAnnotation(id = 2)
public void myMethod2() {
logger.info(">>>>>>>My method2");
}
}
3.3 注解测试
获取方法的注解:两步
(1)通过反射方式获取方法getDeclaredMethods();
(2)通过getAnnotation(MyAnnotation.class)获取方法的注解。
package com.monkey.java_study.annotation;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.lang.reflect.Method;
/**
* 处理方法级注解.
*
* @author xindaqi
* @date 2022-03-17 10:01
*/
public class AnnotationTest {
private static final Logger logger = LoggerFactory.getLogger(AnnotationTest.class);
private static void processAnnotation(Class<?> cl) {
for(Method m : cl.getDeclaredMethods()) {
MyAnnotation myAnnotation = m.getAnnotation(MyAnnotation.class);
if(null != myAnnotation) {
logger.info(">>>>>>>Id: {}", myAnnotation.id());
}
}
}
public static void main(String[] args) {
processAnnotation(AnnotationUsing.class);
}
}
3.4 测试结果
4 参数注解
这里讲解参数检查注解类型:TYPE_USE。
4.1 自定义注解
package com.monkey.java_study.annotation.type_checker;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* 类型检查注解.
*
* @author xindaqi
* @date 2022-03-18 14:56
*/
@Target(ElementType.TYPE_USE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTypeCheckerAnnotation {
String value();
}
4.2 注解应用
package com.monkey.java_study.annotation.type_checker;
/**
* 类型检查应用.
*
* @author xindaqi
* @date 2022-03-18 15:04
*/
@MyTypeCheckerAnnotation(value = "class")
public class TypeCheckerAnnotationUsing {
@MyTypeCheckerAnnotation(value = "name")
private String name;
public String getName() {
return name;
}
public void setName(String name) {
this.name = name;
}
@Override
public String toString() {
return "TypeCheckerAnnotationUsing{" +
"name='" + name + '\'' +
'}';
}
}
4.3 测试
获取属性注解:两步
(1)通过反射获取属性getDeclaredFields();
(2)获取属性注解field.getAnnotatedType().getAnnotation(MyTypeCheckerAnnotation.class)。
这里,使用TYPE_USE标识,需要使用getAnnotatedType()。
package com.monkey.java_study.annotation.type_checker;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import java.beans.PropertyDescriptor;
import java.lang.annotation.Annotation;
import java.lang.reflect.Field;
import java.lang.reflect.Method;
/**
* 类型检查测试.
*
* @author xindaqi
* @date 2022-03-18 15:06
*/
public class TypeCheckerTest {
private static final Logger logger = LoggerFactory.getLogger(TypeCheckerTest.class);
private static void annotationProcess(Class<?> clzz, Object obj) throws Exception {
Annotation[] annotations = clzz.getAnnotations();
for (Annotation annotation : annotations) {
if (annotation instanceof MyTypeCheckerAnnotation) {
logger.info(">>>>>>>>>>Class annotation value:{}", ((MyTypeCheckerAnnotation) annotation).value());
}
}
for (Field field : clzz.getDeclaredFields()) {
if (null != field.getAnnotatedType().getAnnotation(MyTypeCheckerAnnotation.class)) {
PropertyDescriptor propertyDescriptor = new PropertyDescriptor(field.getName(), clzz);
Method readMethod = propertyDescriptor.getReadMethod();
if (null == readMethod.invoke(obj)) {
logger.info(">>>>>>>>>>属性值为null");
}
}
MyTypeCheckerAnnotation myTypeCheckerAnnotation = field.getAnnotatedType().getAnnotation(MyTypeCheckerAnnotation.class);
logger.info(">>>>>>>>>>Field annotation value:{}", myTypeCheckerAnnotation.value());
}
}
public static void main(String[] args) throws Exception {
TypeCheckerAnnotationUsing typeCheckerAnnotationUsing = new TypeCheckerAnnotationUsing();
annotationProcess(typeCheckerAnnotationUsing.getClass(), typeCheckerAnnotationUsing);
}
}
4.4 测试结果
5 小结
- 注解:元信息。提供代码额外信息。
- 注解分为元注解和自定义注解。
- 元注解即注解的注解,用于标识自定义注解,使自定义注解按照既定的轨迹运行。
- 自定义注解即按照开发者需求定义的元信息,如类型检查、数据校验等。
- 自定义注解需要明确注解的作用位置(如类、方法、参数等)、生命周期(如RUNTIME、CLASS等)。