聊聊 Java 注解(上)

Java 语言提供了一个很好的特性 Annotation, 中文常翻译为注解,在平时的编程中也比较常用,最明显的好处就是让代码变得更简洁明了。比如,标记一个函数是否重写了父类方法或者实现了接口的抽象方法,用 @Override 在方法上注解;声明一段函数显示地执行开启事务操作用 @Transaction 注解。

但是注解本身并不是程序的一部分,它并不会对代码的执行有直接的影响,比如把 @Override 注解去掉,重写还有效的,重写本身并不是受 Override 控制的。而像 @Transaction 这种注解去掉后,AutoCommit的设置就会是 true,每条 SQL 就会作为一个事务自动提交。似乎逻辑受影响了?其实不然,而是我们利用了 Spring 的 AOP 的机制,扫描到有 @Transaction 注解的代码,加了一些开启事务、提交事务的逻辑,这个逻辑是在单独的一块代码中实现的,我们只是通过注解来识别了需要加这个逻辑的代码片段。

所以,注解本质上是一种程序的标记行为。

基本概念

Java注解用 @ 符号这种语法形式标记,它由两个基本部分组成:

  1. 名字 ( name )
  2. 元素 ( element )

注解的名字就是一个注解的唯一标识(严格说包含上包名,不同的包下注解名可以重复,但仍是不同的注解),比如 @Override 的名字就是 Override (具体来说是java.lang.Override)。 注解的元素是注解提供一种辅助信息的手段,类似于对象的属性,比

@Qualifier(value = "userService”)

value 就是 Qualifier 的一个元素,这里 value 的值为 userService , 当只有一个元素的时候,元素的名字可以省略:

@Qualifier("userService”)

而当元素有默认值的时候,可以直接省略元素赋值而使用默认值,比如 @Autowired 注解其实有一个默认值为 true 的元素 required. 当然,注解也可以没有任何元素,比如 @Override .

了解了上面的基本概念,基本上就可以轻松地使用注解了,比如我们经常会用 @Autowired 注解标明一个对象的属性值自动从 IoC 容器中获得。但是,只会使用 JDK 或者第三方提供好的注解还不行,我们还需要学会自定义注解。

声明注解

我们以一个 Spring 的 @Autowired 的例子来说明,如何声明一个注解, 请看 Spring 的 @Autowired 源码:

package org.springframework.beans.factory.annotation;

import java.lang.annotation.Documented;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target({ElementType.CONSTRUCTOR, ElementType.FIELD, ElementType.METHOD, ElementType.ANNOTATION_TYPE})
@Retention(RetentionPolicy.RUNTIME)
@Documented
public @interface Autowired {
    boolean required() default true;
}

从例子可以看出,声明一个自定义注解的时候,用 @interface 来标注(没错,很像接口,但不是接口),有 public 这种指明可访问范围的修饰符,有注解的名字 Autowired,有元素声明,同时可以用 default 关键字来设置元素的默认值。

除了名字、元素声明之外,声明一个注解的时候还需要在这个注解之上再加上注解,比如上面例子中的 TargetRetentionDocumented. 这引出了下面一个重要的概念:元注解。

元注解

简单地说,元注解( meta-annotation )就是注解的注解,普通的注解可以修饰类、方法等,而元注解可以修饰注解,甚至包括元注解本身。一个注解是不是元注解的标志为加有 @Target 注解,并且元素 ElementType 包括值ElementType.ANNOTATION_TYPE。

比如 @Documented 是一种元注解,因为被 @Target 标记并且类型为 ANNOTATION_TYPE, 被 @Documented 标记的注解可以被 javadoc 工具识别,而 @Documented 本身也可以被 @Documented 标记:

package java.lang.annotation;

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

Java 标准库中定义的元注解有 5 个:

  • @Retention : 表明注解的保留策略,有三个基本的保留策略
    • RetentionPolicy.SOURCE 源码级别,编译器在编译时会把这类注解剔除
    • RetentionPolicy.CLASS class文件级别,编译时会保留在class文件中,但是 JVM 在执行class文件是忽略这类注解
    • RetentionPolicy.RUNTIME 运行期级别,JVM 会保留这类注解,在运行时能使用这类注解
  • @Documented :被 javadoc 工具识别来生成相关文档
  • @Target : 指明注解作用的 Java 元素
    • ElementType.TYPE

    • ElementType.FIELD

    • ElementType.METHOD

    • ElementType.PARAMETER

    • ElementType.CONSTRUCTOR

    • ElementType.LOCAL_VARIABLE

    • ElementType.ANNOTATION_TYPE

    • ElementType.PACKAGE

    • ElementType.TYPE_PARAMETER

    • ElementType.TYPE_USE

      其中 TYPE_PARAMETER 和 TYPE_USE 都是 Java 8 之后才支持的,即在 Java 8 之前注解只能作用在声明语句上(比如方法声明、类声明),而 Java 8 之后可以作用在类型使用过程中,比如
      str = (@NonNull String) tmp;这种强制类型装换中出现的 @NonNull 注解可以作用在String类型之前,这种语法在 Java 8 之后才会支持。

  • @Inherited :规定注解能否从父类中继承
  • @Repeatable :规定注解是否可以重复,重复型的注解还需要指明注解容器,用来存储可重复性注解,同样也是 Java 8 之后才支持

总结

本篇文章用实例讲解了 Java 中注解(Annotation)的概念,以及一些基本的组成部分,包括注解使用的保留策略、作用的目标元素等;之后重点介绍了元注解的概念以及 Java 标准库中预定义的 5 种元注解,这 5 种元注解代表的含义及其用法,其中要注意有些特性是 Java 8 之后才提供支持的,比如 @Repeatable 注解,使用过程中要注意这一点。

(未完待续, 关注作者追踪下篇)

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

推荐阅读更多精彩内容