注解的概念
注解(Annotation)相当于一种标记,在程序中加入注解就等于为程序打上某种标记,以后,javac编译器、开发工具和其他程序可以通过反射来了解你的类及各种元素上有无何种 标记,看你的程序有什么标记,就去干相应的事,标记可以加在包、类,属性、方法,方法的参数以及局部变量上。
1、定义格式
public @interface 注解名{
}
例:定义一个名为MyInterface的注解
public @interface MyInterface{
}
2、注解的属性
属性的格式
- 格式1:数据类型 属性名();
- 格式2:数据类型 属性名() default 默认值;
// 姓名
String name();
// 年龄
int age() default 18;
// 爱好
String[] hobby();
属性适用的数据类型
* 八种数据数据类型(int,short,long,double,byte,char,boolean,float)
* String,Class,注解类型,枚举类
* 以上类型的数组形式
3、元注解
元注解概述
* Java官方提供的注解
* 用来定义注解的注解
* 任何官方提供的非元注解的定义都使用到了元注解。
常用的元注解
* @Target
* 作用:用来标识注解使用的位置,如果没有使用该注解标识,则自定义的注解可以使用在任意位置。
* 可使用的值定义在ElementType枚举类中,常用值如下
TYPE,类,接口
FIELD, 成员变量
METHOD, 成员方法
PARAMETER, 方法参数
CONSTRUCTOR, 构造方法
LOCAL_VARIABLE, 局部变量
* @Retention
* 作用:用来标识注解的生命周期(有效范围)
* 可使用的值定义在RetentionPolicy枚举类中,常用值如下
* SOURCE:注解只作用在源码阶段,生成的字节码文件中不存在
* CLASS:注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值
* RUNTIME:注解作用在源码阶段,字节码文件阶段,运行阶段
4、使用自定义注解
- 定义一个注解:Book
- 包含属性:String value() 书名
- 包含属性:double price() 价格,默认值为 100
- 包含属性:String[] authors() 多位作者
- 代码实现
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
String value();
double price() default 100;
String[] authros();
}
使用注意事项
- 如果属性有默认值,则使用注解的时候,这个属性可以不用赋值。
- 如果属性没有默认值,那么在使用注解时一定要给属性赋值。
特殊属性value
/**
特殊属性value
* 如果注解中只有一个属性且名字叫value,则在使用该注解时可以直接给该属性赋值,而不需要给出属性名。
* 如果注解中除了value属性之外还有其他属性且只要有一个属性没有默认值,则在给属性赋值时
value属性名也不能省略了。
小结:如果注解中只有一个属性时,一般都会将该属性名命名为value
*/
@interface TestA{
String[] value();
int age() default 100;
String name();
}
@interface TestB{
String name();
}
@TestB(name = "zzz")
@TestA(name = "yyy",value = {"xxx","xxx"})
public class AnnotationDemo02 {
}
5、注解解析
什么是注解解析
* 使用Java技术获得注解上数据的过程则称为注解解析。
与注解解析相关的接口
* Annotation: 注解类,该类是所有注解的父类。
* AnnotatedElement:该接口定义了与注解解析相关的方法
T getAnnotation(Class<T> annotationClass) :
* 根据注解类型获得对应注解对象
Annotation[] getAnnotations():
* 获得当前对象上使用的所有注解,返回注解数组,包含父类继
承的
Annotation[] getDeclaredAnnotations():
* 获得当前对象上使用的所有注解,返回注解数组,只包含本类的
boolean isAnnotationPresent(Class<Annotation> annotationClass):
* 判断当前对象是否使用了指定的注解,如果使用了则返回true,否则false
获取注解数据的原理
* 注解作用在哪个成员上就会得该成员对应的对象来获得注解
* 比如注解作用成员方法,则要获得该成员方法对应的Method对象
* 比如注解作用在类上,则要该类的Class对象
* 比如注解作用在成员变量上,则要获得该成员变量对应的Field对象。
* Field,Method,Constructor,Class等类都是实现了AnnotatedElement接口
代码示例
- 定义注解Book,要求如下:
- 包含属性:String value() 书名
- 包含属性:double price() 价格,默认值为 100
- 包含属性:String[] authors() 多位作者
- 限制注解使用的位置:类和成员方法上
- 指定注解的有效范围:RUNTIME
- 定义MyBook类,在类和成员方法上使用Book注解
- 定义TestAnnotation测试类获取Book注解上的数据
注解book
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
String value();
double price() default 100;
String[] authros();
}
MyBook类
@Book(value = "红楼梦",authros = {"曹雪芹"})
public class MyBook{
@Book(value = "西游记",authros = {"吴承恩","白求恩"},price = 200)
public void showBook(){
}
}
TestAnnotation类
public class TestAnnotation{
/*
获得类上使用的注解数据
*/
@Test
public void test01() throws Exception {
// 获得Class对象
Class c = MyBook.class;
// 判断类上是否使用Book注解
if(c.isAnnotationPresent(Book.class)){
// 根据注解的Class对象获得对应的注解对象
Book annotation = (Book) c.getAnnotation(Book.class);
// 获得书名
System.out.println(annotation.value());
// 获得作者
System.out.println(Arrays.toString(annotation.authros()));
// 获得价格
System.out.println(annotation.price());
}
// 获得当前对象上使用的所有注解,返回注解数组
// Annotation[] annotations = c.getAnnotations();
Annotation[] annotations = c.getDeclaredAnnotations();
System.out.println(Arrays.toString(annotations));
}
/*
获得成员方法上注解的数据
*/
@Test
public void test02() throws Exception {
// 获得Class对象
Class c = MyBook.class;
// 获得成员方法对应的Method对象
Method m = c.getMethod("showBook");
// 根据注解的Class对象获得对应的注解对象
Book annotation = m.getAnnotation(Book.class);
// 获得书名
System.out.println(annotation.value());
// 获得作者
System.out.println(Arrays.toString(annotation.authros()));
// 获得价格
System.out.println(annotation.price());
}
}
以上就是实现自定义注解,以及注解解析的方法,欢迎评论区交流,点赞收藏