java注解核心知识总结

1. 前言

前几年我们的项目还在structs 2 上跑,有一次问一个同事是否知道
Spring Boot,同事说那不是用注解来开发的吗。虽然这个答案并不完全对,但是从客观上Spring Boot对刚刚接触它的人来说最醒目的就是注解了。那么今天我们来了解一下Java语言的核心功能——注解。

2.注解是什么


public @interface Anno {
}

以上就是一个最简单的注解声明。它可以注释到类、接口、方法以及变量上。通过向方法,接口,类或字段添加注释,为其绑定的源代码分配额外的元数据。

3.注解的用途

通过注解我们可以通知编译器有关警告和错误的信息在编译时操作源代码在运行时修改或检查行为。jdk提供内置5个基本注解来处理代码检查。

  • @Override 来标记该方法重写或替换继承的方法的行为。如果你重写了父类方法不带该注解会触发一些警告。
  • @SuppressWarnings 表示我们要忽略部分代码中的某些警告。如忽略潜在的类型不安全转换警告unchecked。
  • @Deprecated 用来表示类、方法已经过时,不推荐使用。如果你强行使用编译器会在编译时进行警告。
  • @Safevarargs 抑制“堆污染”警告。“堆污染”指的是将一个不带泛型的对象赋给带泛型的变量时引发的的类型问题。如果你不想看到该警告就可以使用该注解来抑制。
  • @FunctionalInterface java 8 新增注解,只能作用于接口上来标识该接口是函数式接口。java中函数式接口表示该接口只能有一个抽象方法。如果一个接口被此注解修饰,如果添加第二个抽象方法将无法通过编译。

注解可以将一些元数据传递给你编写的逻辑。比如Spring Mvc 中的一个常用注解@RequestMapping,我们可以通过value参数来传递一个path路径,Spring Mvc通过对请求的路径的匹配来作出是否路由到该path上。 目前大量的的框架都依赖注解,比如Spring、hibernate、dubbo等等。

4.元注解

元注解是可以应用于其他注解的注解。来增强或者配置目标注解的机制。jdk目前提供了5个元注解。如果你需要开发自定义注解,请务必熟悉它们:

  • @Retention 只能用于修饰注解,来指定被修饰注解可以保留多长时间。规定了三种策略:

    • RetentionPolicy.SOURCE 这种策略下被修饰的注解只能存在于源代码中,编译后被丢弃,通过反射无法获取到被修饰的注解。
    • RetentionPolicy.CLASS 这种策略下被修饰的注解会被编译进字节码文件中。但是JVM无法获取到被修饰的注解。这是一个默认值,当你声明的注解没有添加任何保留策略时,会默认指定该策略。
    • RetentionPolicy.RUNTIME 这种策略下被修饰的注解不但可以编译进字节码文件。而且JVM也可以获取被该注解修饰的注解。而且程序编码也可以通过反射来获取被该注解修饰的注解的一些元信息。
  • @Target 用于指定被修饰注解的修饰目标类型。如果一个注解明确了可修饰的目标类型,则只能修饰指定的类型。由枚举ElementType来规定。

  • TYPE 只能修饰 类、接口、枚举。

  • FIELD 只能修饰成员变量,包含枚举内的常量。

  • METHOD 只能修饰方法。

  • PARAMETER 只能修饰参数。

  • CONSTRUCTOR 只能修饰构造器。

  • LOCAL_VARIABLE 只能修饰局部变量。

  • ANNOTATION_TYPE 只能修饰注解。

  • PACKAGE 只能修饰包定义。也就是package-info.java中

  • TYPE_PARAMETER java 8 新增 表示该注解能写在类型参数的声明语句中。 类型参数声明如: <t style="box-sizing: border-box;">、</t>

  • TYPE_USE java 8 新增 注解可以再任何用到类型的地方使用。

  • @Documented 被该注解修饰的注解可以被javadoc工具提取为文档。

  • @Inherited 被该注解修饰的注解有继承性。这里要注意一些要点首先这种继承性体现的类之间而不是接口之间,而且注解必须是对JVM可见。也就是@Retention为RetentionPolicy.RUNTIME 才起作用。

  • @Repeatable java 8 新增。在此之前在同一个元素上同一个注解只能出现一次。@Repeatable可以让一个注解多次出现在一个元素上。

5.自定义注解

自定义注解跟自定义接口类似,但是还有一些区别,实际开发你需要对自定义注解进行元注解注释。注解中的成员变量以无参抽象方法来声明,成员变量并不是所有类型都支持,目前只支持以下类型:

  • 所有基本类型(int,float,boolean,byte,double,char,long,short)

  • String

  • Class (如:Class<?> 或 Class<t style="box-sizing: border-box;">)</t>

  • enum java枚举

  • Annotation

    下面我们就来自定义一个注解:

 /**
 * 声明一个可以标记在类、接口、枚举、方法上的注解。
 * 并且JVM Runtime 可见、可生成文档
 *
 * @author Dax
 * @since 17 :27  2019/9/4
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.TYPE, ElementType.METHOD})
public @interface Anno {
    /**
     * 若方法名为value且注解声明只需要声明value属性时,
     * value可以省略, @Anno("anno") 等同于 @Anno(value="anno")
     *
     * @return the string
     */
    String value();

    /**
     * 一个具有默认值的 String 类型属性。
     * name若不显式声明,则默认值为"" 。  
     * 声明默认值通过 default + 默认值 来声明
     *
     * @return the string
     */
    String name() default "";

    /**
     * 一个Class 类型属性,没有默认值。其他支持类型不再举例
     *
     * @return the class
     */
    Class<?> clazz();
}

如何获取注解中的元数据

所有的注解都是java.lang.annotation.Annotation 的子类。只有RetentionPolicy为RUNTIME的 注解才能通过反射获取。在反射包中提供了AnnotatedElement 接口来对元素上的可捕捉到的注解进行处理。该接口是Class、Method、Constructor等程序元素对象的父接口。也就是说只要能获取程序元素对象就能对其存在的注解进行处理。主要方法有:

  • boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) 判断是否存在 annotationClass类型的注解。
  • <t extends="" annotation="" style="box-sizing: border-box;">T getAnnotation(Class<t style="box-sizing: border-box;"> annotationClass) 如果在当前元素上存在参数所指定类型(annotationClass)的注解,则返回对应的注解,否则将返回null。</t></t>
  • Annotation[] getAnnotations() 返回在这个元素上的所有注解。如果该元素没有注解,则返回值是长度为0的数组。该方法的调用者可以自由地修改返回的数组;它不会对返回给其他调用者的数组产生影响。
  • <t extends="" annotation="" style="box-sizing: border-box;">T[] getAnnotationsByType(Class<t style="box-sizing: border-box;"> annotationClass) 返回与该元素相关联的注解。如果没有与此元素相关联的注解,则返回值是长度为0的数组。这个方法与getAnnotation(Class)的区别在于,该方法检测其参数是否为可重复的注解类型(JLS 9.6),如果是,则尝试通过“looking through”容器注解来查找该类型的一个或多个注解。该方法的调用者可以自由地修改返回的数组;它不会对返回给其他调用者的数组产生影响。参考@Repeatable。</t></t>
  • <t extends="" annotation="" style="box-sizing: border-box;">T getDeclaredAnnotation(Class<t style="box-sizing: border-box;"> annotationClass) 如果参数中所指定类型的注解是直接存在于当前元素上的,则返回对应的注解,否则将返回null。这个方法忽略了继承的注解。(如果没有直接在此元素上显示注释,则返回null。)</t></t>
  • <t extends="" annotation="" style="box-sizing: border-box;">T[] getDeclaredAnnotationsByType(Class<t style="box-sizing: border-box;"> annotationClass) 可获取重复注解但是忽略掉继承注解。</t></t>
  • Annotation[] getDeclaredAnnotations() 跟上面的注解区别在于不能获取重复注解。

基本上对这个接口的方法进行学习后就可以知道如何获取注解的元数据了。下面我们写一个例子,还是上面的Anno注解为例:


/**
 * 被注解标记的类
 **/
@Anno("hello")
public class Foo {}

/**
 * 通过获取Foo 的Class 类,
 * 然后就可以根据上面已经介绍的方法来获取value的值了
 * @author dax
 * @since 2019/9/4 22:17
 */
public class Main {
    public static void main(String[] args) {
        Anno annotation = Foo.class.getAnnotation(Anno.class);

        String value = annotation.value();
        System.out.println("value = " + value);
    }
}

总结

今天我们系统地对注解进行了归纳,相信你已经对注解有了系统性的认识。其实注解还可以干一些花式操作,比如lombok框架。后面我们会介绍相关的注解技术,多多关注。

原创作者:码农小胖哥
转载地址:https://gper.club/articles/7e7e7f7ff7g58gc3g6f

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

推荐阅读更多精彩内容