Java使用@interface定义注解
java用@interface定义注解。在程序中加上注解,JAVAC编译器和VM可以利用它来做一些相应的处理。
元注解
元注解是注解的注解。有如下这一些:
@Retention
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention { /** * Returns the retention policy. * @return the retention policy */ RetentionPolicy value();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
表明带注解类型的注解将会保留多久。如果一个注解类型的声明上没有Retention注解,那么它默认的保留策略是RetentionPolicy.CLASS。
Retention注解有一个属性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
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
(1)SOURCE:表示注解的信息会被编译器丢弃,不会保留在class文件中,注解的信息只会留在源文件中,所以这里注解信息一般都用在编译阶段。
(2) CLASS :表示注解的信息会被编译器记录在class文件中;但在运行时,不会被虚拟机保留着,所以它们不可以用反射的方式读取到;如果不指定Retention的值,默认就是CLASS;
(3)RUNTIME:表示注解的信息会被编译器保留在class文件里;在运行时,还会被虚拟机保留着,所以它们可以用反射的方式读取到,所以这里注解信息一般都用在程序运行阶段;
例子:
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation1 {
}
@Retention(RetentionPolicy.CLASS)
public @interface MyAnnotation2 {
}
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation3 {
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
@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();
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
表明注解类型适用的上下文。如果@Target元注解没有在注解类型上,那么这个注解可以作为一个修饰符用在任何声明上,除了类型参数声明。如有注解类型上有@Target元注解,那么编译器将根据ElementType枚举常量限制它的使用范围。@Target有一个属性ElementType[]类型的属性 value(),就是通过它来指定的。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
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
- 33
- 34
- 35
- 36
- 37
- 38
- 39
- 40
- TYPE: 类、接口(包括注解类型)、枚举声明
- FIELD:字段声明(包括枚举常量)
- METHOD:方法声明
- PARAMETER:形式参数声明
- CONSTRUCTOR:构造函数声明
- LOCAL_VARIABLE:局部变量声明
- ANNOTATION_TYPE:注释类型声明
- PACKAGE:包声明
- TYPE_PARAMETER:类型参数声明
- TYPE_USE:类型的使用
这个@Target元注解表示声明的类型是仅用作复杂注解类型中的成员类型声明。它不能直接用于注释任何内容,如:
@Target({})
public @interface MemberType { ...
}
- 1
- 2
- 3
- 4
综合例子
@Documented
@Retention(CLASS)
@Target({METHOD, PARAMETER, FIELD, LOCAL_VARIABLE, ANNOTATION_TYPE, PACKAGE})
public @interface NonNull {
}
- 1
- 2
- 3
- 4
- 5
我们常自定义用@Retention(RetentionPolicy.RUNTIME) 注释的注解,因为这样的注解会保留在VM中,这样我们才有办法通过反射技术来读取到注解,再做相应处理,事不宜迟,我们来自定义一个:
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation{ String city() default "Test"; String name(); int[] array() default { 2, 4, 5, 6 }; EnumTest.TrafficLamp lamp() ; TestAnnotation lannotation() default @TestAnnotation(value = "ddd"); Class style() default String.class;
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
上面程序中,定义一个注解@MyAnnotation,定义了6个属性,他们的名字为:
city,name,array,lamp,lannotation,style.
属性city类型为String,默认值为gege
属性name类型为String,没有默认值
属性array类型为数组,默认值为2,4,5,6
属性lamp类型为一个枚举,没有默认值
属性lannotation类型为注解,默认值为@TestAnnotation,注解里的属性是注解
属性style类型为Class,默认值为String类型的Class类型
- 1
- 2
- 3
- 4
- 5
- 6
使用注解MyAnnotation:
@MyAnnotation( city= "beijing", name="zhijincheng",array={},lamp=TrafficLamp.RED,style=int.class)
public class TestExample
{ @MyAnnotation(lannotation=@TestAnnotation(value="baby"), name = "zhijincheng",array={1,2,3},lamp=TrafficLamp.YELLOW) @Deprecated @SuppressWarnings("") public void read() { System.out.println("output something!"); }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
通过反射读取注解的信息:
public class MyAnnotationReflection{ public static void main(String[] args) throws Exception{
TestExample testExample = new TestExample(); // 如果TestExample类名上有注解@MyAnnotation修饰,则为true if(TestExample.class.isAnnotationPresent(MyAnnotation.class)){ System.out.println("There is MyAnnotation"); } Class<TestExample> c = TestExample.class; Method method = c.getMethod("read", new Class[] {}); if (method.isAnnotationPresent(MyAnnotation.class)){ // 调用read方法 method.invoke(testExample, null); // 获取方法上注解@MyAnnotation的信息 MyAnnotation myAnnotation = method.getAnnotation(MyAnnotation.class); String city = myAnnotation.city(); String name = myAnnotation.name(); // 打印属性city和name的值 System.out.println(city + ", " + name); // 打印属性array数组的长度 System.out.println(myAnnotation.array().length); // 打印属性lannotation的值 System.out.println(myAnnotation.lannotation().value()); System.out.println(myAnnotation.style()); } // 得到read方法上的所有注解 Annotation[] annotations = method.getAnnotations(); for (Annotation annotation : annotations){ System.out.println(annotation.annotationType().getName()); } }
}
- 1
- 2
- 3
- 4
- 5
- 6
- 7
- 8
- 9
- 10
- 11
- 12
- 13
- 14
- 15
- 16
- 17
- 18
- 19
- 20
- 21
- 22
- 23
- 24
- 25
- 26
- 27
- 28
- 29
- 30
- 31
- 32
谢谢阅读!
文章来源: blog.csdn.net,作者:WongKyunban,版权归原作者所有,如需转载,请联系作者。
原文链接:blog.csdn.net/weixin_40763897/article/details/104289572
- 点赞
- 收藏
- 关注作者
评论(0)