【译】Java Tutorial - 注解

原文地址: Lesson: Annotations

注解

注解(Annotations)是一种类型的元数据,提供和一个程序相关的数据,但是它却不是程序本身,对于程序的代码执行也没有直接影响。

注解有以下几种用途:

  • 给编译器提供信息 - 编译器可以利用注解来检测错误和取消警告(suppress warnings)。
  • 编译时和部署时处理 - 工具软件可以处理注解信息来生成代码,XML文件,等等
  • 运行时处理 - 某些注释可以在运行时被处理

这一教程解释了注解可以被用在哪些地方:如何使用注解;Java 平台有哪些可用的预定义注释;type注释如何与类型可插拔系统一起协作写出支持强类型检查的代码;如何实现可复用的注解。


注解基础知识

注解的格式

最简单的注解如下:

    @Entity

@符号向编译器表面后面跟着的是一条注解。在下面的示例中,Override是一个注解:

    @Override
    void mySuperMethod() {... }

注解也可以包含额外的元素,这些元素可以带名称,也可以不带名称:

    @Author(
     name = "Benjamin Franklin",
     date = "3/27/2003"
      )
      class MyClass() { ... }

或者

    @SuppressWarnings(value = "unchecked")
     void myMethod() { ... }

如果只有一个元素,那么该元素的名称可以省略,它的名称将会被设置为 value

    @SuppressWarnings("unchecked")
    void myMethod() { ... }

如果注解中没有元素,那么括弧也可以省略(如@Override 的例子)。

在一个声明中使用多个注解也是可以的:

@Author(name = "Jane Doe")
@EBook
class MyClass { ... }

如果多个注解具有相同的类型,就称之为重复注解(repeating annotation)

重复注解是Java SE 8 才支持的,查看Repeating Annotations 了解更多关于重复注解的信息。

注解的类型可以是java.lang 或者 java.lang.annotation 包中定义的一个类型。 在之前的例子中,OverrideSuppressWarnings 是 Java预定义的注解(预定义的Java注解),你也可以定义你自己的注解类型,之前示例中的AuthorEbook 注解就是自定义的注解。

注解可以被用在什么地方

注解可以被用在声明上,如类声明,类属性声明,方法声明,还有其他的程序元素。 当注解应用于声明是,一个注解通常占据单独的一行。

在JavaSE 8 Release 中,注解也可以被用在类型的使用上,如:

  • 类实例创建表达式:

      new @Interned MyObject();
    
  • 类型转换:

       myString = (@NonNull String) str;
    
  • implements 子句:

        class UnmodifiableList<T> implements 
      @Readonly List<@Readonly T> { ... }
    
  • 异常抛出语句:

      void monitorTemperature() throws
      @Critical TemperatureException { ... }
    

这些格式的注解被称之为类型注解。 你可以查看 Type Annotations and Pluggable Type Systems 了解更多信息。


声明注解类型

许多注解用于替换代码中的注释。

设想有一个软件组织在每个类的内容开始部分使用注释提供一些重要的信息,如下:

public class Generation3List extends Generation2List {

   // Author: John Doe
   // Date: 3/17/2002
   // Current revision: 6
   // Last modified: 4/12/2004
   // By: Jane Doe
   // Reviewers: Alice, Bill, Cindy

   // class code goes here

}

为了使用注解来添加相同的元数据,首先你需要有一个 注解类型。 可以通过如下格式定义:

@interface ClassPreamble {
   String author();
   String date();
   int currentRevision() default 1;
   String lastModified() default "N/A";
   String lastModifiedBy() default "N/A";
   // Note use of array
   String[] reviewers();
}

注解的定义和接口的定义方式很像,不过注解的 interface 关键词前面有一个(@)。 实际上注解类型也是一种interface,这个在后面会说明,但是现在你并不需要理解这一点。

示例中的注解定义包含了注解类型元素 定义,它看起来很像一个方法,但是它可以定义默认值。

在定义了注解类型之后,你就可以使用它了,如:

@ClassPreamble (
   author = "John Doe",
   date = "3/17/2002",
   currentRevision = 6,
   lastModified = "4/12/2004",
   lastModifiedBy = "Jane Doe",
   // Note array notation
   reviewers = {"Alice", "Bob", "Cindy"}
)
public class Generation3List extends Generation2List {

// class code goes here

}

提示: 为了使@ClassPreamble 中的信息可以出现在生成的java doc 中,你必须在@ClassPreamble 的定义前加上@Docmented 注解:

// import this to use @Documented
import java.lang.annotation.*;

@Documented
@interface ClassPreamble {

   // Annotation element definitions
   
}

预定义的注解类型

Java SE API 中已经预定义了一系列的注解类型。其中一些被java编译器读取使用,还有一些用于其他的注解。

被Java 语言使用的注解

java.lang包里定义了以下注解: @Deprecated@Override@SupressWarnings

@DePrecated @Deprecated 注解表示被其标记的元素已经废弃,不应该再被使用。 当使用一个被@Deprecated 标记的类/方法/变量时,编译器会生成一个警告。 当一个元素被废弃时,在它的Javadoc 注释中也应该使用@Deprecated 注解标记,如下面的示例代码所示. Javadoc中使用的@ 符号和注解中使用@符号并非巧合,实际上它们是相关联的概率。 另外,请注意 javadoc中@后的内容以一个小写的d开头,而注解中的是大写的 D

   // Javadoc comment follows
    /**
     * @deprecated
     * explanation of why it was deprecated
     */
    @Deprecated
    static void deprecatedMethod() { }
}

@Override @Override 注解告诉编译器被注解的元素覆盖了超类的对应的声明。(方法覆盖在 Interfaces and Inheritance 中说明)

   // mark method as a superclass method
   // that has been overridden
   @Override 
   int overriddenMethod() { }

但是,在覆盖方法时并不强制要求使用这个注解,它只是用来预防错误。 如果一个方法被@Override 标记却没有正确的覆盖超类的对应方法,那么编译器就会生成一个错误。

@SupressWarnings @SupressWarnings 注解禁止编译器产生本来应该产生的警告。下面的例子使用了一个被抛弃的方法,所以编译器会产生一条警告,但是 @SupressWarnings 注解能禁止编译器产生这条警告。

   // use a deprecated method and tell 
   // compiler not to generate a warning
   @SuppressWarnings("deprecation")
    void useDeprecatedMethod() {
        // deprecation warning
        // - suppressed
        objectOne.deprecatedMethod();
    }

每一个警告都属于一个类别,而Java 语言规范列出了两种警告类别:
deprecationunchecked,在与泛型出现之前旧代码交互时可能会出现未检查的警告。
你也可以在一个@SuppressWarnings注解中禁止多个种类的警告:

@SuppressWarnings({"unchecked", "deprecation"})// 注意其中的"{}"

@SafeVarags@SafeVarags 注解被用于方法或者构造函数时,表示代码没有对 varargs 参数做潜在的不安全操作,当使用这个注解时, 和varargs 相关的unchecked 警告将会被禁止。

@FunctionalInterface Java SE8 引入了@FunctionalInterface 注解,用于指示指定的元素是Java语言规范定义的功能接口(Functional interface)。

应用在其他注解上的注解

应用在其他注解上的注解被称之为 元注解(meta_annotations)java.lang.annotation 中定义了一些元注解:
@Retention @Retention注解指定被标记的注解如何存储:

  • RetentionPolicy.SOURCE - 只在源代码中保存,而编译器会忽略
  • RetentionPolicy.CLASS - java 编译器在编译时保存,但JVM会忽略。
  • RetentionPolicy.RUNTIME - JVM 会保存,因此可以在运行时环境中使用(runtime environment)

@Documented @Documented 注解指示JavaDoc工具处理时被标记的元素应该生成文档。(默认情况下注解不会包包含到javadoc中),你可以查看 Javadoc tools page 获取更多信息。

@Target @Target 注解用于限制其他注解可以使用的元素,可以使用的值如下:

  • ElementType.ANNOTATION_TYPE 可以使用在任何元素上
  • ElementType.CONSTRUCTOR 使用于构造函数
  • ElementType.FIELD 类成员或属性
  • ElementType.LOCAL_VARIABLE 本地变量
  • ElementType.METHOD 方法级别的注解
  • ElementType.PACKAGE 包声明
  • ElementType.PARAMETER 方法的参数
  • ElementType.TYPE一个类的任何元素 (any element of a class)

@Inherited @Inherited 默认情况下子类是没有继承父类的注解信息的,而使用此注解后,子类会继承父类的注解。使用了@Inherited 注解后,当用户查询类中的注解信息时,如果没有找到相应类型的注解信息,则会去父类中查询。@Inherited 注解只用于类声明上的注解。

@Repeatable @Repeatable 注解时 Java SE 8 引入的, 表被声明的注解可以在一个元素声明上使用多次。更多信息可以查看 Repeating Annotations


关于@FunctionalInterface注解:

最后编辑于
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 219,427评论 6 508
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 93,551评论 3 395
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 165,747评论 0 356
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,939评论 1 295
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,955评论 6 392
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,737评论 1 305
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,448评论 3 420
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 39,352评论 0 276
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,834评论 1 317
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,992评论 3 338
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 40,133评论 1 351
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,815评论 5 346
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,477评论 3 331
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 32,022评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 33,147评论 1 272
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 48,398评论 3 373
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 45,077评论 2 355

推荐阅读更多精彩内容

  • 本文章涉及代码已放到github上annotation-study 1.Annotation为何而来 What:A...
    zlcook阅读 29,163评论 15 116
  • 什么是注解(Annotation):Annotation(注解)就是Java提供了一种元程序中的元素关联任何信息和...
    九尾喵的薛定谔阅读 3,168评论 0 2
  • 整体Retrofit内容如下: 1、Retrofit解析1之前哨站——理解RESTful 2、Retrofit解析...
    隔壁老李头阅读 6,509评论 4 31
  • 内容概要 Annotation的概念 Annotation的作用 Annotation的分类 系统内置注解 元注解...
    DevinZhang阅读 4,172评论 0 28
  • 四季中只有它,在蝉声孜孜不倦的呼唤中,才会睡眼朦胧的出现。为了迎接它,土地里的生命此起彼伏的跳出来,一同伸展了一个...
    潺禅阅读 415评论 5 3