Java高级系列——注解(Annotations)

2018年01月13日 :: RonTech 阅读数 3405更多
所属专栏: Java高级系列文章

 版权声明:转载请注明出处,谢谢配合。 https://blog.csdn.net/zyhlwzy/article/details/79052514

学习一下 不了解这个东西呢. 

一、介绍

本系列文章的这一部分我们将会介绍Java 5版本引入的除泛型和枚举之外的另外一个强大特性:注解,可以将注解看成一种特殊的接口。

注解是一种特殊种类的元数据,它能够关联Java语言中不同元素和结构。有意思的是,在Java生态系统中大多数使用样板XML描述符的地方,注解在消除这些XML描述符上做出了很大的贡献。注解引入了新的,类型安全以及非常强健的配置和个性化技术。

二、注解作为特殊接口

就像我们在前文中所提到的一样,注解用来关联Java语言中的元数据和不同的元素。

注解本身对它所注解的元素不会造成任何直接的影响。但是,依靠注解和它的定义方式,它们可以被Java编译器(注解最好的实例就是我们前面的文章中所使用的@Override注解)、注解处理器和运行时代码使用反射和其他的虚拟机内省技术使用。

让我们来看一个最简单的注解声明:

public @interface SimpleAnnotation {
}

@interface关键字引入了新的注解类型,这也是为何注解可以被当做专门的接口看待,注解可以声明有默认值和没有默认值的属性,比如:

public @interface SimpleAnnotationWithAttributes {
    String name();
    ;
}

如果注解声明了没有默认值的属性,那么在该注解被应用的所用地方都应该提供注解属性值。

@SimpleAnnotationWithAttributes(name = "new annotation")

为了方便,如果注解只有一个属性并且属性的名称是value,那么属性的名称就可以被省略,比如:

public @interface SimpleAnnotationWithValue {
    String value();
}

上面声明的这个注解就可以按照如下的方式去使用:

@SimpleAnnotationWithValue("new annotation")

  

注解也有一些限制,在某些情况下使用注解可能会不太方便。

  • 首先,注解不支持任何继承:注解不能继承其他的注解。

  • 其次,不能通过编码的形式使用new关键字创建注解实例。

  • 第三,注解只能声明基本数据类型属性,String或者 Class<?>类型及其数组。

  • 第四,注解中不允许声明方法和构造器。

三、注解及其保留策略(Retention Policy)

每个注解都有一个被称为保留策略(Retention Policy)的特征,它是一组如何保留注解的策略组合的枚举(RetentionPolicy类型)。保留策略可以设置为以下的值之一。

策略 描述
CLASS 注解被编译器记录在class文件中,但是在运行时不需要虚拟机保留(即运行时不存在)
RUNTIME 注解被编译器记录在class文件中并且在运行时被虚拟机保留,因此可以通过反射机制获取
SOURCE 注解被编译器丢弃(即注解仅在源码中保留,class文件中不存在)

保留策略对注解何时可用于处理有至关重要的影响。保留策略可以通过使用@Retention注解来设置。比如:

import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;

@Retention( RetentionPolicy.RUNTIME )
public @interface AnnotationWithRetention {
}

  

设置注解的保留策略为RUNTIME将会保证注解在编译过程和运行的应用程序中存在。

四、注解以及元素类型(ElementType)

注解的另外一个特征就是每个注解必须有它能够应用的元素类型。有点类似于保留策略,元素类型被定义成一组可能的元素类型的枚举(ElementType)。

元素类型 描述
ANNOTATION_TYPE 标明注解可用于注解类型声明(应用于另外的注解)
CONSTRUCTOR 标明注解可用于构造函数声明
FIELD 标明注解可用于字段/域(包括枚举常量)声明
LOCAL_VARIABLE 标明注解可用于局部变量声明
METHOD 标明注解可用于方法声明
PACKAGE 标明注解可用于包声明
PARAMETER 标明注解可用于参数声明
TYPE 标明注解可用于类、接口(包括注解类型)、枚举类型的声明

此外,除了上面所描述的这些元素类型之外,Java 8版本引入了两个新的注解可以使用的元素类型。

元素类型 描述
TYPE_PARAMETER 标明注解可以写在类型变量的声明语句中
TYPE_USE 表示该注解能写在使用类型的任何语句中(eg:声明语句、泛型和强制转换语句中的类型)

和保留策略对比,注解可以使用@Target注解声明多个与之相关联的多个元素类型。比如:

import java.lang.annotation.ElementType;
import java.lang.annotation.Target;

@Target({ElementType.FIELD, ElementType.METHOD})
public @interface AnnotationWithTarget {
}

大多数情况下,您要创建的所有注解都应该同时指定保留策略和元素类型才能有用。

五、注解与继承(Annotations and inheritance)

在Java中,声明注解与继承之间存在非常重要的联系。默认情况下,子类不能够继承父类中声明的注解,但是,有一种方法就是可以通过使用@Inherited注解在类层次结构中传递指定的注解。比如:

@Target( { ElementType.TYPE } )
@Retention( RetentionPolicy.RUNTIME )
@Inherited
@interface InheritableAnnotation {
}

@InheritableAnnotation
public class Parent {
}

public class Child extends Parent {
}

在这个例子中,被声明在父类中的@InheritableAnnotation注解可以被子类继承。

六、可重复注解(Repeatable annotations)

我们到目前为止还没有讨论过Java 8之前的版本和注解相关的另外的一个限制,即相同的注解在同一个地方只能出现一次,不能重复多次。Java 8通过提供可重复注解的支持放松了这种限制。比如:

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
public @interface RepeatableAnnotations {
RepeatableAnnotation[] value();
}

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable( RepeatableAnnotations.class )
public @interface RepeatableAnnotation {
    String value();
};

@RepeatableAnnotation("repeatition 1")
@RepeatableAnnotation("repeatition 2")
public void performAction() {
    // Some code here
}

虽然在Java 8中可重复注解功能需要做一些工作才能使注解可重复使用(使用@Repeatable),但最终的结果是值得的:更简洁和紧凑的注释代码。

七、注解处理器(Annotation processors)

Java编译器支持一种称为注解处理器的特殊类型的插件(使用-processor命令行参数),它可以在编译阶段处理注解。 注解处理器可以分析注解的作用(执行静态代码分析),创建额外的Java源文件或资源(可以被编译和处理),或者改变注解的代码。

在告知编译器那个注解可以被注解处理器应用和处理,保留策略(Retention Policy)扮演了非常关键的角色。

注释处理器被广泛使用,但是编写一个注解处理器需要一些关于Java编译器如何工作和编译过程本身的知识。

八、注解与配置大于约定(Annotations and configuration over convention)

约定大于配置是一种软件设计惯例,这种惯例旨在简化开发过程,但是开发者需要遵循一些简单的规则(或约定)。比如说,一些MVC框架遵循约定将控制器放在controller目录(或者包)中,一些ORM框架经常遵循约定在model目录查找实体类并从各自的类中获取关系表名称。

另一方面,注解开创了一种不同的设计惯例,即一切基于明确的配置。就我们上面所说的例子而论,@Controller注解可以明确的标记任何类作为控制器,@Entity注解可以关联数据库表。注解的好处也来自于这样的事实,即注解的可拓展性、可拥有额外属性和有限的特定元素类型。Java编译器会强制执行不当的注解使用并在编译阶段很早就发现错误配置问题。

九、何时使用注解

注解实际上无处不在:Java标准库有很多,基本上每个Java规范都包含注解。 每当您需要将附加的元数据与您的代码相关联,注解都是简单直接的方法。

有趣的是,Java社区正在不断努力开发公共通用语义概念并通过多种技术标准(更多信息,请参阅JSR-250规范)化注解。目前,标准Java库中包含以下注解。

注解 描述
@Deprecated 表明被标记元素已过期并应该不再使用。每当程序使用被该注解注解的方法、类或字段(域)时,编译器会生成警告。
@Override 提示编译器该元素是为了覆盖在父类中声明的元素。
@SuppressWarnings 指示编译器抑制通过其他方式生成的警告。
@SafeVarargs 当应用于方法或构造函数时,声明代码不会对其可变参数执行潜在的不安全操作。使用此注解类型时,与可变参数使用有关的未经检查的警告将被抑制。
@Retention 指定如何保留被标记的注解。
@Target 指定被标记注解可以使用那些Java元素
@Documented 表明使用该注解的元素可以使用Javadoc工具记录(默认情况下,注解是不包含在Javadoc中的)
@Inherited 表明注解类型可以从父类继承

Java 8版本的发布增加了也增加了几个新的注解。

注解 描述
@FunctionalInterface 表示类型声明是按照Java语言规范定义的函数接口。
@Repeatable 表明被标记的注解可以在相同的地方应用多次。

十、小结

本文我们大概讲述了一些和注解相关内容,通过本文的阅读我们大致可以明白注解可以作为一个特殊的接口,在定义一个新的注解是,我们需要指定注解的保留策略以及元素类型。同时我们也阐述了如何让子类继承父类的注解以及如何声明可重复注解。当然我们也讲述了一些关于注解处理器以及在注解所遵从的配置大于约定的概念。接下来我们将会讨论如何有效的编写方法,敬请期待。

[转帖]Java高级系列——注解(Annotations)的更多相关文章

  1. JAVA高级特性 - 注解

    注解是插入到代码中用于某种工具处理的标签.这些标签可以在源码层次上进行操作,或者可以处理编译器将其纳入到注解类文件中. 注解不会改变对程序的编译方式.Java编译器会对包含注解和不包含注解的代码生成相 ...

  2. Java高级特性——注解,这也许是最简单易懂的文章了

    最近,浪尖在做flink的项目时source和sink的绑定那块用到了注解,当然新版本1.6以后就变为server load的方式加载. 但是浪尖也是觉得很有毕业讲一下注解,毕竟高级免试也会问答的吧. ...

  3. Java开发系列-注解

    概述 在JDK5之后提供了一个新特性,和类.接口同级.定义时使用的关键字是@interface.注解主要有三个作用,分别是编译检查.替代配置文件.定义注解(元注解).分析代码(用到反射).注解的本质就 ...

  4. Java高级特性——注解(Annotation)

    文件地址:https://github.com/xiaozhengyu/StudyNotes.git

  5. 夯实Java基础系列15:Java注解简介和最佳实践

    Java注解简介 注解如同标签 Java 注解概述 什么是注解? 注解的用处 注解的原理 元注解 JDK里的注解 注解处理器实战 不同类型的注解 类注解 方法注解 参数注解 变量注解 Java注解相关 ...

  6. Java高级特性 第6节 注解初识

    一.注解概述 Java注解也就是Annotation,是Java代码里的特殊标记,它为Java程序代码提供了一种形式化的方法,用来表达额外的某些信息,这些信息是代码本身无法表示的. 注解以标签的形式存 ...

  7. [转帖]java注解核心知识总结

    java注解核心知识总结 2019-11-01 20:39:50 从事Java 阅读数 2  收藏 文章标签: java注解总结程序员 更多 分类专栏: java 注解   版权声明:本文为博主原创文 ...

  8. 夯实Java基础系列9:深入理解Class类和Object类

    目录 Java中Class类及用法 Class类原理 如何获得一个Class类对象 使用Class类的对象来生成目标类的实例 Object类 类构造器public Object(); register ...

  9. Spring源码系列 — 注解原理

    前言 前文中主要介绍了Spring中处理BeanDefinition的扩展点,其中着重介绍BeanDefinitionParser方式的扩展.本篇文章承接该内容,详解Spring中如何利用BeanDe ...

随机推荐

  1. BZOJ3514 Codechef MARCH14 GERALD07加强版 LCT+可持久化线段树

    自己独自想出来并切掉还是很开心的~ Code: #include <bits/stdc++.h> #define N 400005 #define inf 1000000000 #defi ...

  2. Spring Boot系列目录

    1.spring mvc 接口动态注入 FactoryBean ImportBeanDefinitionRegistrar ClassPathScanningCandidateComponentPro ...

  3. Dean and Schedule (URAL 2026)

    Problem A new academic year approaches, and the dean must make a schedule of classes for first-year ...

  4. 在eclipse中查找一个类中的方法在其他哪个类中被调用了

    选中你所要查看的方法名,ctrl+shift+G就可以查看所有调用过该方法的地方了.在Search视图里面可以查看得到这个样子是可以的,你也可以按Ctrl+H全文检索一下

  5. AcWing:237. 程序自动分析(离散化 + 并查集)

    在实现程序自动分析的过程中,常常需要判定一些约束条件是否能被同时满足. 考虑一个约束满足问题的简化版本:假设x1,x2,x3,…x1,x2,x3,…代表程序中出现的变量,给定n个形如xi=xjxi=x ...

  6. 中间件 | kafka简介、使用场景、设计原理、主要配置及集群搭建

    开源Java学习 公众号 一.入门 1.简介 Kafka is a distributed,partitioned,replicated commit logservice.它提供了类似于JMS的特性 ...

  7. LC 740. Delete and Earn

    Given an array nums of integers, you can perform operations on the array. In each operation, you pic ...

  8. [Ubuntu]18安装navicat 破解版&官方版本

    破解版本: 一.下载破解版的navicat  链接:https://pan.baidu.com/s/1ulptSderoG0EbEQpO3Adww提取码:8oc3 二.解压到桌面 在下载压缩文件之后, ...

  9. python中requests.session的妙用

    在进行接口测试的时候,我们会调用多个接口发出多个请求,在这些请求中有时候需要保持一些共用的数据,例如cookies信息. 1.requests库的session对象能够帮我们跨请求保持某些参数,也会在 ...

  10. Jmeter联机负载时报错: connection refused to host localhost,nested exception is:java.net ConnectException:Connection refused:connect

    Jmeter联机负载时报错: connection refused to host localhost,nested exception  is:java.net ConnectException:C ...