傻瓜,自定义注解你会写了吗?(2)

简介: 傻瓜,自定义注解你会写了吗?(2)

@Retention注解

用于描述注解的生命周期,表示注解在什么范围有效,它有3个取值:

  1. Java源文件阶段;
  2. 编译到class文件阶段;
  3. 运行期阶段。

同样使用了RetentionPolicy枚举类型定义了三个阶段:

public enum RetentionPolicy {
    /**
     * Annotations are to be discarded by the compiler.
     * (注解将被编译器忽略掉,常见的@Override就属于这种注解)
     */
    SOURCE,
    /**
     * Annotations are to be recorded in the class file by the compiler
     * but need not be retained by the VM at run time.  This is the default
     * behavior.
     * (注解将被编译器记录在class文件中,但在运行时不会被虚拟机保留,这是一个默认的行为。@Deprecated和@NonNull就属于这样的注解)
     */
    CLASS,
    /**
     * Annotations are to be recorded in the class file by the compiler and
     * retained by the VM at run time, so they may be read reflectively.
     * (注解将被编译器记录在class文件中,而且在运行时会被虚拟机保留,因此它们能通过反射被读取到;@Controller、@Service等都属于这一类)
     * @see java.lang.reflect.AnnotatedElement
     */
    RUNTIME
}

@Documented

将注解的元素加入Javadoc中

@Inherited

是指定某个自定义注解如果写在了父类的声明部分,那么子类的声明部分也能自动拥有该注解。@Inherited注解只对那些@Target被定义为ElementType.TYPE的自定义注解起作用。

@Repeatable

表示该注解可以重复标记

注解的特殊语法

1.如果注解本身没有注解类型元素,那么在使用注解的时候可以省略(),直接写为:@注解名,它和标准语法@注解名()等效!

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface FirstAnnotation {
}

使用

//等效于@FirstAnnotation()
@FirstAnnotation
public class JavaBean{
  //省略实现部分
}


2.如果注解本本身只有一个注解类型元素,而且命名为value,那么在使用注解的时候可以直接使用:@注解名(注解值),其等效于:@注解名(value = 注解值)

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface SecondAnnotation {
  String value();
}

使用

//等效于@FirstAnnotation()
@FirstAnnotation
public class JavaBean{
  //省略实现部分
}

3.如果注解中的某个注解类型元素是一个数组类型,在使用时又出现只需要填入一个值的情况,那么在使用注解时可以直接写为:@注解名(类型名 = 类型值),它和标准写法:@注解名(类型名 = {类型值})等效

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.TYPE})
@Documented
public @interface ThirdAnnotation {
  String[] name();
}


使用案例

//等效于@ ThirdAnnotation(name = {"this is third annotation"})
@ ThirdAnnotation(name = "this is third annotation")
public class JavaBean{
  //省略实现部分
}

4.如果一个注解的@Target是定义为Element.PACKAGE,那么这个注解是配置在package-info.java中的,而不能直接在某个类的package代码上面配置

自定义注解的运行时解析

只有当注解的保持力处于运行阶段,即使用@Retention(RetentionPolicy.RUNTIME)修饰注解时,才能在JVM运行时,检测到注解,并进行一系列特殊操作。

自定义的注解@CherryAnnotation,并把它配置在了类Student上

@Retention(RetentionPolicy.RUNTIME)
@Target(value = {ElementType.METHOD})
@Documented
public @interface CherryAnnotation {
    String name();
    int age() default 23;
    int[] score();
}

Student

public class Student {
    @CherryAnnotation(name = "peng",age = 23,score = {99,66,77})
    public void study(int times){
        for(int i = 0; i < times; i++){
            System.out.println("Good Good Study, Day Day Up!");
        }
    }
}

反射操作获取注解

public class Test {
    public static void main(String[] args){
        try {
            //获取Student的Class对象
            Class stuClass = Class.forName("cn.jp.pojo.Student");
            //说明一下,这里形参不能写成Integer.class,应写为int.class
            Method stuMethod = stuClass.getMethod("study",int.class);
      //判断该元素上是否配置有CherryAnnotation注解;
            if(stuMethod.isAnnotationPresent(CherryAnnotation.class)){
                System.out.println("Student类上配置了CherryAnnotation注解!");
                //获取该元素上指定类型的注解
                CherryAnnotation cherryAnnotation = stuMethod.getAnnotation(CherryAnnotation.class);
                System.out.println("name: " + cherryAnnotation.name() + ", age: " + cherryAnnotation.age()
                    + ", score: " + cherryAnnotation.score()[0]);
            }else{
                System.out.println("Student类上没有配置CherryAnnotation注解!");
            }
        } catch (ClassNotFoundException e) {
            e.printStackTrace();
        } catch (NoSuchMethodException e) {
            e.printStackTrace();
        }
    }
}

如果我们要获得的注解是配置在方法上的,那么我们要从Method对象上获取;如果是配置在属性上,就需要从该属性对应的Field对象上去获取,如果是配置在类型上,需要从Class对象上去获取。总之在谁身上,就从谁身上去获取!


反射对象上还有一个方法getAnnotations(),该方法可以获得该对象身上配置的所有的注解。它会返回给我们一个注解数组,需要注意的是该数组的类型是Annotation类型,这个Annotation是一个来自于java.lang.annotation包的接口。

注解的核心原理

按照注解的生命周期以及处理方式的不同,通常将注解分为运行时注解和编译时注解

编译时注解通过注解处理器来支持,而注解处理器的实际工作过程由JDK在编译期提供支持,有兴趣可以看看javac的源码。

注解的内容就大致介绍到这吧~~~~~~~~

有兴趣的老爷,可以关注我的公众号【一起收破烂】,回复【006】获取2021最新java面试资料以及简历模型120套哦~

相关文章
|
4天前
|
监控 NoSQL Java
面试官:实际工作中哪里用到了自定义注解?
面试官:实际工作中哪里用到了自定义注解?
55 2
|
6月前
|
JSON 安全 Java
SpringMVC之自定义注解(这期博客带你领略自定义注解的魅力)
SpringMVC之自定义注解(这期博客带你领略自定义注解的魅力)
47 0
SpringMVC之自定义注解(这期博客带你领略自定义注解的魅力)
|
7月前
|
前端开发 Java 编译器
Java的第十六篇文章——枚举、反射和注解(后期再学一遍)
Java的第十六篇文章——枚举、反射和注解(后期再学一遍)
|
XML 缓存 Java
Java注解怎么用
Java注解怎么用
204 0
|
消息中间件 JavaScript 小程序
项目终于用上了插入式注解,真香!
项目终于用上了插入式注解,真香!
项目终于用上了插入式注解,真香!
|
Java Spring 容器
Spring框架:第六章:注解功能
Spring框架:第六章:注解功能
Spring框架:第六章:注解功能
|
Java API Spring
傻瓜,自定义注解你会写了吗?(1)
傻瓜,自定义注解你会写了吗? (1)
傻瓜,自定义注解你会写了吗?(1)
|
数据采集 算法 Java
今天拿SpringAOP和自定义注解的通用性开🔪
SpringAOP和自定义注解的通用性
90 0
今天拿SpringAOP和自定义注解的通用性开🔪
|
NoSQL Java 程序员
想自己写框架?不会写Java注解可不行
想自己写框架?不会写Java注解可不行
想自己写框架?不会写Java注解可不行