自定义注解

自定义一个注解:

@Inherited
@Documented
@Target({ElementType.CONSTRUCTOR,ElementType.TYPE,ElementType.FIELD,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

	long id();
	String name();
	boolean gender() default true;
	String[] hobbies();
	
}

在interface前加一个@符号,表明这是一个注解类型,在这里注解名字为MyAnnotation。在MyAnnotation注解的定义里包括四个属性,分别是id,name,gender和hobbies。乍一看,这四个属性的声明和接口的方法签名类似,有返回类型和方法名,不过还是存在一些差别。首先是注解对返回的数据类型有规定,只能限定为原始类型,String,Class,Annotation,Enum和类型为以上的一维数组,复杂对象(包括原始类型的封装类型,如Integer)是不允许的。另外可以对属性设置默认值,只需在属性后添加default关键字,并赋予一个对应类型的默认值。增加默认机制的好处是,如果接受默认值,则可以省略该属性。


在注解上面添加的注解告诉如何使用该注解。其中比较重要的是@Target和@Retention。

@Target告诉该注解的位置。

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}

从@Target的定义可以看出,该注解只包含一个数据类型为ElementType的数组的属性。ElementType是一个包含了8个常量的枚举类型。

public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

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

    /** Method declaration */
    METHOD,

    /** Parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE
}

如果你想要自定义注解放置在方法上,只需将常量ElementType.METHOD放进@Target注解的属性中。

@Target({ElementType.METHOD...})

public @interface MyAnnotation {

...

}

当然,除了可以放在方法上以外,还可以放置到构造器,包,局部变量,参数,类,接口等。在ElementType枚举的常量中,基本上都能从变量名猜出它的作用,不过有两个不是很清楚,它们是ANNOTATION_TYPE和TYPE。TYPE表名注解可以放置到类,接口(包括注解)和枚举上,而ANNOTATION_TYPE(可以想象成是TYPE的子集)只能放置到注解上(比如@Target)。


@Retention注解告诉被注解的注解的驻留时间,该时间是通过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
}

RetentionPolicy包括三个常量,SOURCE,CLASS和RUNTIME。其中默认的是CLASS。

SOURCE告诉该注解的有效范围是源代码。

CLASS告诉该注解的有效范围是源代码和字节码文件。

RUNTIME告诉注解的有效范围是源代码,字节码和JVM运行时。(可以通过反射获取元数据信息)


如果想通过反射机制获取注解的元信息,必须将设置为RUNTIME。

假设将上面的注解添加到MyApplication类上:

@MyAnnotation(name="benson",id=123,hobbies={"basketball","volleyball","bowling"})
public class MyApplication {


}

那么如何可以获取到上面的数据呢(benson,123,basketball...)

答案是通过反射。前提是该注解的保留决策是RUNTIME类型的。

	public static void main(String[] args) {
		Class myApplication = MyApplication.class;
		Annotation[] annotations = myApplication.getAnnotations();
		
		for(Annotation annotation : annotations) {
			if(annotation instanceof MyAnnotation) {
				MyAnnotation myAnnotation = (MyAnnotation) annotation;
				System.out.println("name:" + myAnnotation.name());
				System.out.println("id:" + myAnnotation.id());
				System.out.println("hobbies:" + Arrays.toString(myAnnotation.hobbies()));
			}
		}
	}

打印结果:

name:benson
id:123
hobbies:[basketball, volleyball, bowling]

另外,如果一个注解只有一个属性,一个惯例是将该属性的名字设置为value,比如

public @interface MyAnnotation {

    String value();

}

这样做的好处是,当你在注解时为该属性提供值时,无须再提供属性名,比如:

@MyAnnotation("happy")

Class ABC {

}

以上等价于

@MyAnnotation(valule="happy")

Class ABC {

}


  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值