Java自定义注解Annotation

本文详细介绍了Java注解的概念,包括元注解@Documented、@Target、@Retention和@Inherited的用法。通过示例展示了如何定义和使用自定义注解,以及在运行时如何处理注解。强调了注解在类、方法、字段等不同位置的使用,并讨论了注解的保留策略和继承特性。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

一、注解(Annotation)概述

注解是放在Java源码的类、方法、字段、参数前的一种特殊“注释”。

注释会被编译器直接忽略,注解则可以被编译器打包进入class文件,因此,注解是一种用作标注的“元数据”。

Java从JDK5.0开始便提供了四个meta-annotation用于自定义注解的时候使用,这四个注解为:@Target,@Retention,@Documented 和@Inherited。

二、元注解

元注解是给注解进行注解,或者说注解可以修饰其他注解,可以理解为注解的注解就是元注解。

@Documented

是一个标记注解,木有成员,用于描述其它类型的annotation应该被作为被标注的程序成员的公共API,因此可以被例如javadoc此类的工具文档化。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

@Target

最常用的元注解是@Target。@Target用于描述注解的使用范围(即:被描述的注解能够被应用于源码的哪些位置):

@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();
}
@Target 注解只有唯一成员value,类型为ElementType数组。ElementType可取的值有:
public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}
TYPE:用于描述类、接口(包括注解类型)enum声明
FIELD:用于描述成员变量
METHOD:用于描述方法
PARAMETER:用于描述参数
CONSTRUCTOR:用于描述构造器
LOCAL_VARIABLE:用于描述局部变量
 ANNOTATION_TYPE:注释类型声明
 PACKAGE:用于描述包

@Retention

指定被描述的注解在什么范围内有效,即定义了Annotation的生命周期。

如果@Retention不存在,则该Annotation默认为CLASS。因为通常我们自定义的Annotation都是RUNTIME

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

RetentionPolicy可取的值

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     */
    SOURCE,

    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     */
    CLASS,

    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     *
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}
SOURCE:在源文件中有效(即源文件保留);

CLASS:在class文件中有效(即class保留);

RUNTIME:在运行时有效(即运行时保留)。

@Inherited

使用@Inherited定义子类是否可继承父类定义的Annotation。@Inherited仅针对@Target(ElementType.TYPE)类型的annotation有效,并且仅针对class的继承,对interface的继承无效

某个被标注的类型是被继承的。如果一个使用了@Inherited修饰的annotation类型被用于一个class,则这个annotation将被用于该class的子类。类A被@Inherited标注 , 类B继承类A , 则类B默认也定义了该注解

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

三、定义Annotation

用@interface定义注解

public @interface CustomAnnotation {
   
}

定义参数、默认值 ,核心参数使用value名称

public @interface CustomAnnotation {
 	String name() default "";
    String description() default "";
}

用元注解配置注解

必须设置@Target来指定Annotation可以应用的范围

应当设置@Retention(RetentionPolicy.RUNTIME)便于运行期读取该Annotation
@Target({ElementType.FIELD,ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface CustomAnnotation {
    String name() default "";
    String description() default "";
}

使用注解

@CustomAnnotation(name = "Student",description="这是Student类")
public class Student implements Serializable{

	@CustomAnnotation(name = "name",description="这是name属性")
	private String name;

	@CustomAnnotation(name = "getName",description = "获取name属性")
	public String getName() {
		return name;
	}
	public void setName(String name) {
		this.name = name;
	}
}

处理注解

    public static void main(String[] args) {
        Class<Student> aClass = Student.class;
        //是否被@CustomAnnotation标注
        if (aClass.isAnnotationPresent(CustomAnnotation.class)) {
            //获取@CustomAnnotation注解对象
            CustomAnnotation annotation = aClass.getAnnotation(CustomAnnotation.class);

            // 获取@CustomAnnotation注解所对应的方法与值
            try {
                Method method1 = CustomAnnotation.class.getMethod("name");
                String name = (String) method1.invoke(annotation);
                System.out.println(name);

                Method method2 = CustomAnnotation.class.getMethod("description");
                String description = (String) method2.invoke(annotation);
                System.out.println(description);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }

        Method[] methods = aClass.getMethods();
        for (Method method : methods) {
            if (method.isAnnotationPresent(CustomAnnotation.class)) {
                CustomAnnotation annotation = method.getAnnotation(CustomAnnotation.class);
                System.out.println(annotation.name());
                System.out.println(annotation.description());
            }
        }

        Field[] declaredFields = aClass.getDeclaredFields();
        for (Field declaredField : declaredFields) {
            if (declaredField.isAnnotationPresent(CustomAnnotation.class)) {
                CustomAnnotation annotation = declaredField.getAnnotation(CustomAnnotation.class);
				System.out.println(annotation.name());
				System.out.println(annotation.description());

                String type = null;
                // 判断类型
                if (int.class.isAssignableFrom(declaredField.getType()) || Integer.class.isAssignableFrom(declaredField.getType())) {
                    type = "Integer";
                } else if (String.class.isAssignableFrom(declaredField.getType())) {
                    type = "String";
                }
                System.out.println(type);
            }
        }
    }

注意事项

Annotation的成员定义必须满足以下三点:

成员只能用public或默认(default)这两个访问权修饰;

成员的类型只能是基本类型,String,Enum,Class,Annotation以及它们的数组类型;

如果只有一个成员,最好将其名称设为value。

常用注解方法

<T extends Annotation> T getAnnotation(Class<T> annotationType) // 根据annotationType获取注解对象

Annotation[] getAnnotations() // 获取所有注解

boolean isAnnotationPresent(Class<T> annotationType) // 判断当前元素是否被annotationType注解

Annotation[] getDeclareAnnotations() // 与getAnnotations() 类似,但是不包括父类中被Inherited修饰的注解
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

CodeDevMaster

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值