元注解的概念
元注解是用于修饰其他注解的注解。
(1)元注解本身也是注解。
(2)元注解是用来修饰别的注解的。
JDK5.0提供了四种元注解:
@Retention
@Target
@Documented
@Inherited
比如JDK内置的3个注解之一:
@SuppressWarnings
就有元注解:
元注解_@Retention
看源码:
配置参数:
RetentionPolicy value();
RetentionPolicy是一个枚举类型
@Retention:用于修饰注解,用于指定修饰的那个注解的生命周期,@Rentention包含一个RetentionPolicy枚举类型的成员变量,使用@Rentention时必须为该value成员变量指定值:
RetentionPolicy.SOURCE
在源文件中有效(即源文件保留),编译器直接丢弃这种策略的注释,在.class文件中不会保留注解信息
案例:
比如我自己定义了一个注解叫做MyAnno01:
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnno01 {
String[] value();
}
并且MyAnno01用Retention元注解修饰,并且传入参数RetentionPolicy.SOURCE,表示在源文件中有效。
然后设置一个Person测试类:(使用MyAnno01)
@MyAnno01({"abc","def"})
public class Person {
String name;
int age;
public void eat(){
System.out.println("hhhhh");
}
}
然后重新构建这个项目:
在out目录中,找到Person类的class文件:
发现没有注解
这就是 RetentionPolicy.SOURCE 的效果。
RetentionPolicy.CLASS
在class文件中有效(即class保留),保留在.class文件中,但是当运行Java程序时,他就不会继续加载了,不会保留在内存中,JVM不会保留注解。如果注解没有加Retention元注解,那么相当于默认的注解就是这种状态。
案例:还是刚才的例子,将Retention元注解传入参数RetentionPolicy.CLASS,表示在字节码文件中有效。
@Retention(RetentionPolicy.CLASS)
public @interface MyAnno01 {
String[] value();
}
重新编译或者构建项目:(发现在字节码文件中,这个注解仍旧存在)
RetentionPolicy.RUNTIME
在运行时有效(即运行时保留),当运行 Java程序时,JVM会保留注释,加载在内存中了,那么程序可以通过反射获取该注释。
元注解_@Target
用于修饰注解的注解,用于指定被修饰的注解能用于修饰哪些程序元素。@Target也包含一个名为value的成员变量。
@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
}
ElementType是一个枚举类型,并且有以下几个参数:TYPE,FIELD,METHOD,PARAMETER,CONSTRUCTOR,LOCAL_VARIABLE,ANNOTATION_TYPE,PACKAGE,TYPE_PARAMETER,TYPE_USE
案例:
准备一个注解:
用@Target修饰:(注意我传参是TYPE,METHOD,CONSTRUCTOR)
@Target({TYPE,METHOD,CONSTRUCTOR})
public @interface MyAnno02 {
}
然后准备一个Dog类:
@MyAnno02
public class Dog {
@MyAnno02
String name;
int age;
String Type;
@MyAnno02
public Dog(String name, int age, String type) {
this.name = name;
this.age = age;
Type = type;
}
@MyAnno02
public void bark(){
System.out.println("wawawawawawa");
}
}
发现在成员变量这里是报错的:
所以例子就大概说明了@Target注解的作用。
在报错的前提下,如果加上@Target中的FIELD参数:
@Target({TYPE,METHOD,CONSTRUCTOR,FIELD})
public @interface MyAnno02 {
}
这时候就不会报错了:
上面演示了TYPE,METHOD,CONSTRUCTOR,FIELD这四个参数的用法:
TYPE:类、接口(包括注释类型)或枚举声明
METHOD:方法声明
CONSTRUCTOR:构造函数声明
FIELD:字段声明(包括枚举常量)
还有其他参数:
LOCAL_VARIABLE:局部变量声明
ANNOTATION_TYPE:注释类型声明
TYPE_USE:类型的使用
TYPE_PARAMETER:
PACKAGE:包声明
PARAMETER:形式参数声明
元注解_@Documented
用于指定被该元注解修饰的注解类将被javadoc工具提取成文档。默认情况下,javadoc是 不包括注解的,但是加上了这个注解生成的文档中就会带着注解了
案例:
Documented注解修饰了Deprecated注解
(Deprecated注解的源码)
那么Deprecated注解就会在javadoc提取的时候,提取到API中:
比如Date类的 setSeconds 方法就使用了Deprecated注解:
API:
元注解_@Inherited
被它修饰的Annotation将具有继承性。如果某个类使用了被
@Inherited修饰的Annotation,则其子类将自动具有该注解。
案例:
注解:如果MyAnno01注解使用了@Inherited之后,就具备了继承性,那么相当于Person的子类Student也使用了这个MyAnno
@Inherited
@Retention(RetentionPolicy.CLASS)
public @interface MyAnno01 {
String[] value();
}
父类:
子类:
注意:@Documented和@Inherited实际使用较少
框架=注解+反射+设计模式。