一、注解的作用
- 对Java中的类、方法、成员变量做标记,然后进行特殊处理,至于到底做何种处理由业务需求来决定。
二、自定义注解--格式
- 自定义注解就是自己做一个注解来使用
public @interface MyAnnotation {
public 属性类型 属性名() default 默认值;
}
特殊属性
- value属性,如果只有一个value属性的情况下,使用value属性的时候可以省略value名称不写
- 但是如果由多个属性,且多个属性没有默认值,那么value名称是不能省略的。
例子:
package com.gg.annotation_01;
/**
* @Author: {LZG}
* @ClassName: MyAnnotation
* @Description: TODO
* @Date: 2022/6/21 9:51
**/
public @interface MyAnnotation {
String name();
String[] authors();
double price();
}
package com.gg.annotation_01;
/**
* @Author: {LZG}
* @ClassName: MyAnnotationTest
* @Description: TODO
* @Date: 2022/6/21 9:55
**/
@MyAnnotation(name = ("java"),authors = {"张三","李四"},price = 199.9)
public class MyAnnotationTest {
@MyAnnotation(name = ("java"),authors = {"张三","李四"},price = 199.9)
public MyAnnotationTest(){}
@MyAnnotation(name = ("java"),authors = {"张三","李四"},price = 199.9)
public static void main(String[] args) {
@MyAnnotation(name = ("java"),authors = {"张三","李四"},price = 199.9)
int age=21;
}
}
三、元注解
元注解:就是放在注解上边的注解
常用元注解:
- @Target:约束自定义注解只能在那些地方使用
@Target中可以使用的值定义在Elementtype枚举类中,常用值如下
- TYPE -- 类,接口
- FIELD -- 成员变量
- METHOD -- 成员方法
- PARSMETER -- 方法参数
- CONSTRUCTOR -- 构造器
- LOCAL_VARIABLE -- 局部变量
- @Retention:申明注解的生命周期
@Rentention中可以使用的值定义在RetentionPolicy枚举类中,常用值如下
- SOURCE -- 注解值作用在源码阶段,生成的字节码文件中不存在
- CLASS -- 注解作用在源码阶段,字节码文件阶段,运行阶段不存在,默认值。
- RUNTIME -- 注解作用在源码阶段,字节码文件阶段,运行阶段(开发常用)。
例子
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTest {
}
四、注解解析
- 注解的的操作中经常需要进行解析,注解的解析就是判断是否存在注解,存在注解就解析出内容
与注解相关的接口
- Annotation -- 注解的顶级接口,注解都是Annotation类型的对象
- AnnotationElement -- 该接口定义了与注解解析相关的解析方法
方法 | 说明 |
---|---|
Annotation[] getDeclareAnnotations() | 获得当前对象使用的所有注解,返回注解数组 |
T getDeclareAnnotation(Class<T> annotationClass) | 根据注解类型获得对应注解对象 |
boolean isAnnotationPresent(Class<Annotation> annotationClass) | 判断当前对象是否使用了指定的注解,如果使用了,则返回ture,否则返回false |
- 所有的类成分Class、Method、Field、Constructor,都实现了AnnotationElement 接口他们都拥有解析注解的能力
解析注解的技巧
- 注解在那个成分上,我们就先拿那个成分对象
- 比如主角儿作用成员方法,则要获得该成员方法对应的Method对象,再来拿上面的注解
- 比如注解作用在类上,则要该类的Class对象,再来拿上面的注解
- 比如注解作用在成员变量上,则要获得该车官员变量对应的Field对象,再来拿上面的注解
注解解析的案例
- 定义注解Book,要求如下:
- 包含属性:String value 书名
- 包含属性:double price() 价格,默认值为100
- 包含属性:String[] authors() 多位作者
- 限制注解使用的位置:类和成员方法上
- 指定注解的有效范围:RUNTIME - 定义BookStore类,在类和成员方法上使用Book注解
- 定义AnnotationTest测试类获取Book注解上的数据
注解定义
package com.gg.annotation_02;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
/**
* @Author: {LZG}
* @ClassName: Book
* @Description: TODO
* @Date: 2022/6/21 10:36
**/
@Target({ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface Book {
String value();
double price() default 100;
String[] authors();
}
定义类并使用注解
package com.gg.annotation_02;
/**
* @Author: {LZG}
* @ClassName: BookStore
* @Description: TODO
* @Date: 2022/6/21 10:39
**/
@Book(value = "高数",price = 50,authors = {"李四"})
public class BookStore {
@Book(value = "现代",price = 99.9,authors = {"张三","王五"})
public void test(){
}
}
注解解析
package com.gg.annotation_02;
import java.lang.annotation.Annotation;
import java.lang.reflect.Method;
/**
* @Author: {LZG}
* @ClassName: AnnotationTest
* @Description: TODO
* @Date: 2022/6/21 10:43
**/
public class AnnotationTest {
public static void main(String[] args) throws NoSuchMethodException {
// 1. 先得到类对象
Class bookStoreClass = BookStore.class;
Method method = bookStoreClass.getMethod("test");
// 2. 判断这个类是否存在这个注解
if (bookStoreClass.isAnnotationPresent(Book.class)){
// 3. 直接获取该注解对象
Book book = (Book)bookStoreClass.getDeclaredAnnotation(Book.class);
for (String author:book.authors()){
System.out.println(author);
}
System.out.println(book.value());
System.out.println(book.price());
}
if (method.isAnnotationPresent(Book.class)){
// 3. 直接获取该注解对象
Book book = (Book)method.getDeclaredAnnotation(Book.class);
for (String author:book.authors()){
System.out.println(author);
}
System.out.println(book.value());
System.out.println(book.price());
}
}
}
执行结果