Java注解

Java注解

内容参考:

【注解】Annotation Target ElementType

https://www.cnblogs.com/baiqiantao/p/7469746.html

在这篇博客里已经将注解解释的相当详细, 在此基础上进行一定的增删.

加之在 Java编程思想这本书中, 有一章节专门用来介绍注解, 感兴趣的话可以看一下.

基础

在java中,注解作为程序的元数据嵌入到程序当中, 元数据标签的存在并不影响程序代码的编译和执行。

注解可以被一些解析工具或者是编译工具进行解析, 其信息可以在编译、加载和运行时被读取(具体详见元注解 Retention),并执行相应的处理。

什么是元数据

元数据(Metadata),又称中介数据、中继数据,为描述数据的数据(data about data),主要是描述数据属性(property)的信息,用来支持如指示存储位置、历史数据、资源查找、文件记录等功能.

其余地方就不再引用, 如注解的优缺点, 和XML文件的对比. 从这里已经有了基本的核心. 用来描述数据的数据.

在研究Java注解的具体功用, 特性等, 不如从案例开始;

public @interface TestAnnotation {
}

通过这种方式我们就定义了一个注解, @interface. 我们来看一个熟悉的注解:

@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Component
public @interface Controller {
    String value() default "";
}

这是Spring中的 @Controller注解, 那我们怎样解读这个注解呢?

@Controller("test")
//@Controller(value = "test")
public class TestController() {

}

使用方法解读

在编程思想中有一句很有趣的话, 如果没有处理解读注解的工具, 注解也不会比注释来的更有用处.

在真正解读之前,在这里提出几点关于注解的说明, 注解本身是类似于Java接口的, 但是有几点区别 :

  1. 注解的成员变量以无形参的方法形式来声明, 在这里表示的意思就是, 它是个成员变量, 长得像方法, 因此不要想着各种各样的实现, 其方法名和返回值定义了该成员变量的名字和类型。
  2. 成员变量的类型限定为:基本类型、String、Enums、Annotation(但不能是自身)或者是这些类型的数组, 甚至于返回值也可以是注解.
  3. 使用注解时, 需要为所有的成员变量都进行赋值, 除非使用default关键字设置默认值
  4. 当 成员变量 value 为唯一的需要被赋值的属性值(也就是只有value设置default时), 此时在使用时无需使用键值对的形式.(示例见下文)
  5. 注解可以被用来注解其他注解. 甚至可以注解自身.

对注解有了这些基本的了解, 继续来看, 如何解读一个注解?在我目前的理解中, 反射.

//定义注解, 在这里需要指定为RUNTIME, 否则无法通过反射获取到.
//因为反射特点之一就是 运行时执行.
@Retention(RetentionPolicy.RUNTIME)
    public @interface TopClass {
        String name();
        String username() default "zzzxxxx";
}

@TopClass(name = "zzzzzz")
    public class AnnotationTest {
}

public class ReadAnnotation {

    public static void main(String[] args) {

        TopClass tp = AnnotationTest.class.getAnnotation(TopClass.class);

        System.out.println(tp.name());
        System.out.println(tp.username());
    }
}

结果输出 zzzzzz; zzzxxxx;

同时在 Class类中, 还有几种有关注解的处理方式, 就不多介绍了.而 Method, Field等其他类中都实现了对应的方法.

因此在Spring中指定了扫描的包, 会扫描对应的Class, 找到相应的注解, 创建相应的实例, 这种流程也就不难理解了.

元注解

Java为我们提供了4种元注解(元注解专门用来注解其他注解):

@Target, @Retention, @Documented, @Inherited

  1. 如:

    @Documented
    @Retention(RetentionPolicy.RUNTIME)
    @Target(ElementType.ANNOTATION_TYPE)
    public @interface Target {
    ElementType[] value();
    }

元注解

  1. @Target

    这个注解被用来指定 注解可以用在什么地方.

    其值 ElementType 表示类型:

     public enum ElementType {
         TYPE,           // 类, 接口(包括注解类型)或enum声明 
         FIELD,          // 域声明, 包括enum实例
         LOCAL_VARIABLE, // 局部变量
         METHOD,         // 方法声明
         PACKAGE,        // 包声明
         PARAMETER,      // 参数声明
         CONSTRUCTOR,    // 构造器声明
         ANNOTATION_TYPE,// 作用目标是注解
         TYPE_PARAMETER, // 看了好久都不明白, 这两个1.8注解的具体作用
         TYPE_USE        //
     }
    

    而元注解本身都有 @Target(ElementType.ANNOTATION_TYPE) 所注解.

    而如果不声明, 则可以用于任何地方.但在 Java8以后,如果不声明的话, TYPE_PARAMETER, TYPE_USE 所适合的场景并不能使用 相应注解.

  2. Retention 保留策略

     @Documented
     @Retention(RetentionPolicy.RUNTIME)
     @Target(ElementType.ANNOTATION_TYPE)
     public @interface Retention {
         RetentionPolicy value();
     }
    
     public enum RetentionPolicy {
    
         SOURCE,         //表明注解会被编译器忽略
         CLASS,          //表明注解仅在编译时使用, 在运行时被抛弃.
         RUNTIME         //编译及运行时都会保留相应注解, 反射可用.
     }
    

    默认值为: CLASS; 反射时必须指定为 RUNTIME;

  3. Documented 文档化

  4. Inherited 自动继承

    指明如果父类使用了 被元注解 注解 的 注解, 此注解会被继承. 如果使用注解类型注解类以外的任何事物,此元注解类型都是无效的。还要注意,此元注解仅促成从超类继承注解;对已实现接口的注解无效。

目前来说就这么多, 依然遗留问题是, 1.8 ElementType中新添加的两个对象.

posted @ 2018-04-09 15:18  千江月09  阅读(188)  评论(0编辑  收藏  举报