注解学习回顾及初步总结

136 阅读4分钟
  • 注解的概念

    为Java代码提供元数据,对Java代码进行标记,配合其他技术,达到简化代码、修改逻辑、扩展功能等目的一段固定格式的标记型代码

  • 注解的定义

    平时我们基本上都是使用他人框架中编写好的注解来进行开发,在我们感叹这注解真**的好用的时候是不是也想过他们是咋写的呢,其实别人也是安装注解定义的常规方式去编写,把他们的想法通过代码呈现出来,实际上我们也是可以做到的(指实现自己的想法)

    • 关键字

      @interface

      平时我们定义一个类用class,同样的我们定义一个注解就用上面这个关键字就ok了。并且,注解的本质其实就是一个继承自Annotation接口的接口,只是他特殊一些(至于他这么特殊底层是怎么实现的还没研究)。

      所以,一个注解这样写就定义好了,可以拿去到处用了(拿着一边玩去~)。

      public @interface HappyAnnotation { }
      
    • 元注解(圆柱姐)

      就像孩子生下来要管教,注解定义之后也是要对它设置一些约束

      • @Retention

        这个注解规定了注解信息能保留到哪个阶段(是的,注解不好好规定是会不见的)

        取值范围固定三个

        1. RetentionPolicy.SOURCE

          源码中、编译期

        2. RetentionPolicy.CLASS

          字节码中、类加载前

        3. RetentionPolicy.RUNTIME

          运行中

      • @Target

        给注解规定能作用的地方(不能啥地方都能标记上,注解满天飞了都)

        取值范围固定8个

        1. ElementType.TYPE

          类、接口、枚举、注解(头)上

        2. ElementType.FIELD

          成员变量、枚举常量上

        3. ElementType.METHOD

          方法上

        4. ElementType.PARAMETER

          方法的参数上

        5. ElementType.CONSTRUCTOR

          构造函数上

        6. ElementType.LOCAL_VARIABLE

          局部变量上

        7. ElementType.ANNOTATION_TYPE

          注解上(跟1重叠了,更细化的控制?)

        8. ElementType.PACKAGE

          这个注解比较特殊,并不是注解在一般类头部包的包名上(会报错),而是注解在某个包下的package-info.java文件中的包名上,关于这个文件简单解释一下,他不是一个普通的类文件,无法通过正常创建类的方式创建,因为类名中包含“-”,需要通过创建普通file文件的方式创建,这个文件主要是用来存放一些包权限的常量和类,进行集中管理,并且可以提供包层级的注释,对这个包的功能作用等进行注释说明,并且在这个类的包名上可以进行包注解,为包注解提供便利

        9. ElementType.Type_PARAMETER

          泛型声明上(即尖括号内)

        10. ElementType.Type_USE

          到处乱七八糟能用,搞不懂

      • @Document

        将注解中的元素包含到javadoc中去

      • @Inherited

        作用在注解上,被@Inherited注解的注解在注解父类时,子类自动继承该注解,但子类可以重写该注解

      • @Repeated

        作用在注解上,使被注解的注解可作用在同一个目标上多次

        但这个注解用起来比较绕(那是相当滴绕啊),我们来看demo

        @Retention(RetentionPolicy.RUNTIME)
        @Target(ElementType.TYPE)
        public @interface FruitBasket {
            Fruit[] value();
        }
        
        @Retention(RetentionPolicy.RUNTIME)
        @Target(ElementType.TYPE)
        @Repeatable(FruitBasket.class)
        public @interface Fruit {
            String value();
        }
        
        @Fruit("apple")
        @Fruit("orange")
        public class Person { }
        

        FruitBasket注解是用来装可重复注解Fruit注解的容器,同时也是一个注解,然后要求属性是待承装注解的一维数组

        Fruit注解是我们的目标注解,用@Repeated进行注解,后面跟的属性就是刚刚我们定义的FruitBasket注解,这是一个固定的写法。然后就可以欢乐地使用了

        值得注意的是我们使用反射来获取修饰Person类的时候得到的是FruitBasket注解而不是Fruit注解

        public static void main(String[] args) {
            for (Annotation annotation : new Person().getClass().getAnnotations()) {
                System.out.println(annotation);
            }
            //打印输出:
            //@com.tthappy.annotation.FruitBasket(
            //      value=[
            //          @com.tthappy.annotation.Fruit(value=apple), 
            //          @com.tthappy.annotation.Fruit(value=orange)
            //      ]
            //)
        
            for (Fruit fruit : new Person().getClass().getAnnotation(FruitBasket.class).value()) {
                System.out.println(fruit.value());
            }
            //打印输出:
            //apple
            //orange
        }
        
    • 注解的属性

      定义一个注解,除了需要元注解的加持,同时也需要定义属性来为注解提供足够的信息

      • 属性的本质

        从上文中我们知道了注解的本质其实就是一个接口,那注解的属性会是接口中的什么呢,是成员变量吗,不,注解的属性本质上是接口的方法

      • 属性的定义

        其实上面的例子中就包含了很多属性定义的实例

      • 属性类型的约束

        属性的类型是有一定约束的,只能是下面的这几种:

        1. 基本数据类型

        2. String类型

        3. 枚举类型

        4. Class类型

        5. Annotation类型

        6. 以上类型的一维数组类型