3个步骤:
-
定义注解
-
使用注解
-
获取注解信息做各种牛逼的事情
定义注解
关于注解的定义,先来几个问题:
-
如何为注解定义参数?
-
注解可以用在哪里?
-
注解会被保留到什么时候?
定义注解语法
jdk中注解相关的类和接口都定义在java.lang.annotation
包中。
注解的定义和我们常见的类、接口类似,只是注解使用@interface
来定义,如下定义一个名称为MyAnnotation
的注解:
public @interface MyAnnotation {
}
注解中定义参数
注解有没有参数都可以,定义参数如下:
public @interface 注解名称{
[public] 参数类型 参数名称1() [default 参数默认值];
[public] 参数类型 参数名称2() [default 参数默认值];
[public] 参数类型 参数名称n() [default 参数默认值];
}
注解中可以定义多个参数,参数的定义有以下特点:
-
访问修饰符必须为public,不写默认为public
-
该元素的类型只能是基本数据类型、String、Class、枚举类型、注解类型(体现了注解的嵌套效果)以及上述类型的一位数组
-
该元素的名称一般定义为名词,如果注解中只有一个元素,请把名字起为value(后面使用会带来便利操作)
-
参数名称后面的
()
不是定义方法参数的地方,也不能在括号中定义任何参数,仅仅只是一个特殊的语法 -
default
代表默认值,值必须和第2点定义的类型一致 -
如果没有默认值,代表后续使用注解时必须给该类型元素赋值
指定注解的使用范围:@Target
使用@Target注解定义注解的使用范围,如下:
@Target(value = {ElementType.TYPE,ElementType.METHOD})
public @interface MyAnnotation {
}
上面指定了MyAnnotation
注解可以用在类、接口、注解类型、枚举类型以及方法上面,自定义注解上也可以不使用@Target注解,如果不使用,表示自定义注解可以用在任何地方。
看一下@Target
源码:
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
ElementType[] value();
}
有一个参数value,是ElementType类型的一个数组,再来看一下ElementType
,是个枚举,源码如下:
package java.lang.annotation;
/注解的使用范围/
public enum ElementType {
/类、接口、枚举、注解上面/
TYPE,
/字段上/
FIELD,
/方法上/
METHOD,
/方法的参数上/
PARAMETER,
/构造函数上/
CONSTRUCTOR,
/本地变量上/
LOCAL_VARIABLE,
/注解上/
ANNOTATION_TYPE,
/包上/
PACKAGE,
/类型参数上/
TYPE_PARAMETER,
/类型名称上/
TYPE_USE
}
指定注解的保留策略:@Retention
我们先来看一下java程序的3个过程
-
源码阶段
-
源码被编译为字节码之后变成class文件
-
字节码被虚拟机加载然后运行
那么自定义注解会保留在上面哪个阶段呢?可以通过@Retention
注解来指定,如:
@Retention(RetentionPolicy.SOURCE)
public @interface MyAnnotation {
}
上面指定了MyAnnotation
只存在于源码阶段,后面的2个阶段都会丢失。
来看一下@Retention
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}
有一个value参数,类型为RetentionPolicy枚举,如下:
public enum RetentionPolicy {
/注解只保留在源码中,编译为字节码之后就丢失了,也就是class文件中就不存在了/
SOURCE,
/注解只保留在源码和字节码中,运行阶段会丢失/
CLASS,
/源码、字节码、运行期间都存在/
RUNTIME
}
使用注解
语法
将注解加载使用的目标上面,如下:
@注解名称(参数1=值1,参数2=值2,参数n=值n)
目标对象
直接来案例说明。
无参注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Ann1 { //@1
}
@Ann1 //@2
public class UseAnnotation1 {
}
@1:Ann1为无参注解
@2:类上使用@Ann1注解,没有参数
一个参数的注解
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Ann2 { //@1
String name();
}
@Ann2(name = “我是路人甲java”) //@2
public class UseAnnotation2 {
}
一个参数为value的注解,可以省略参数名称
只有一个参数,名称为value的时候,使用时参数名称可以省略
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Ann3 {
String value();//@1
}
@Ann3(“我是路人甲java”) //@2
public class UseAnnotation3 {
}
@1:注解之后一个参数,名称为value
@2:使用注解,参数名称value省略了
数组类型参数
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@interface Ann4 {
String[] name();//@1
}
@Ann4(name = {“我是路人甲java”, “欢迎和我一起学spring”}) //@2