自定义注解
权限修饰符 @interface 注解名字{
// 注解体定义
属性类型 属性名();
属性类型 属性名();
属性类型 属性名();
......
}
属性类型:
基本数据类型
String类型
Class类型
注解类型
枚举类型
以及以上类型的数组形式
虽然注解和接口确实共享了同一个关键字,但它们在实际使用中具有不同的目的和功能,可谓千差万别
元注解
元注解的概念来源于元数据,
元数据:用于解释数据的数据,就是元数据 meta data
元注解:用来修饰自定义注解的注解(注解的注解)
常用元注解:
@Retention元注解,来定义我们自定义注解的保留级别.
- RetentionPolicy.RUNTIME 一直保留到运行阶段
- RetentionPolicy.CLASS 默认 保留到字节码文件阶段,运行阶段不存在
- RetentionPolicy.SOURCE 只作用在源码阶段,字节码文件中不存在
@Target元注解,声明被修饰的自定义注解只能在哪些位置使用
@Target(ElementType.TYPE) // 修饰自定义的MyTest注解,表示MyTest注解只能用在类上
public @interface MyTest {
}
- 类、接口 ElementType.TYPE
- 成员变量 ElementType.FIELD
- 构造方法 ElementType.CONSTRUCTOR
- 成员方法 ElementType.METHOD
- 方法参数 ElementType.PARAMETER
- 局部变量 ElementType.LOCAL_VARIABLE
注解的使用
语法:@注解名(属性1=属性值,属性2=属性值)
解释:
- 使用的时候注解需要通过@符号进行实例化,"@"可以认为相当于“new”关键字,必不可少。
- 注解相当于给Java代码打上一个标签,所以它必须要修饰Java代码的一个结构。比如修饰一整个类,一整个方法,一个成员变量等等。
- 实例化注解时,必须给注解的各个属性赋值,赋值方式是:属性名 = 属性值。如果是数组类型的注解属性,用"{}“赋值。如果有多个属性,赋值时用”,"隔开。如果属性类型是引用类型, 不能是null
注意事项:
- 每个属性都要赋值
- 可以不赋值,但是要有默认值, default
- 数组形式赋值 {}
- 如果只有1个属性, 名字叫value, 可以简化赋值
- 如果属性类型是引用类型, 不能是null
示例
public class Demo {
// 这5个注解都是加在m1方法上的
// 每个属性都要赋值
@MyAnnotation1(name = "张三", age = 30)
// 可以不赋值,但是要有默认值, default
@MyAnnotation2(name = "李四")
@MyAnnotation3
// 数组形式赋值 {}
@MyAnnotation4(name = {"王五", "赵六"})
// 如果只有1个属性, 名字叫value, 可以简化赋值
@MyAnnotation5("钱七")
public void m1() {
}
}
// 自定义注解
@interface MyAnnotation1 {
String name();
int age();
}
@interface MyAnnotation2 {
String name();
int age() default 20;
}
@interface MyAnnotation3 {
String name() default "张三";
int age() default 18;
}
@interface MyAnnotation4 {
String[] name();
}
@interface MyAnnotation5 {
String value();
}
注解的解析
注解的解析:就是判断类上、方法上、成员变量上是否存在注解,并把注解的内容给解析出来,通过反射获取注解信息,根据注解信息进行处理。
// 获取当前对象上面的所有注解
public Annotation[] getDeclaredAnnotation()
// 获取指定的注解对象
public T getDeclaredAnnotation(Class<T> annotationClass)
// 判断当前对象上是否有某个注解
public boolean isAnnotationPresent(Class<Annotation> annotationClass)
基本逻辑
- 获取注解所加的类的Class对象
- 通过Class对象获取注解所加的类中的结构(Filed, Constructor, Method)对象
- 通过该结构对象判断是否使用了注解
- 通过该结构对象获取注解实例
- 通过注解实例获取注解信息
public class Demo {
public static void main(String[] args) throws Exception{
// 获取字节码文件对象
Class<?> c = Class.forName("_24annotation.com.cskaoyan._04handle.Demo");
// 拿到方法对象
Method loginMethod = c.getDeclaredMethod("login");
// 判断方法上是否使用了注解
boolean annotationPresent = loginMethod.isAnnotationPresent(Login.class);
if (annotationPresent) {
// 获取注解实例
Login loginAnnotation = loginMethod.getAnnotation(Login.class);
// 获取属性值
String password = loginAnnotation.password();
String username = loginAnnotation.username();
// 打印
System.out.println(password);
System.out.println(username);
}else {
System.out.println("没有使用注解");
}
}
@Login
public static void login(){
}
}
// 定义注解
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.METHOD)
@interface Login{
// 属性
String username() default "admin";
String password() default "123456";
}