Java 注解 您所在的位置:网站首页 对xml的理解 Java 注解

Java 注解

2024-03-26 16:42| 来源: 网络整理| 查看: 265

Java 注解 —— 注解的理解、注解的使用与自定义注解

参考网址:

《秒懂,Java 注解 (Annotation)你可以这样学》 《Java注解基本原理》 《注解Annotation实现原理与自定义注解例子》 《框架开发之Java注解的妙用》

一. 注解基本介绍 1.1 什么是注解?

什么是注解?严谨的来说,注解提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。 Java 注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。注解包含在 java.lang.annotation 包中。 具体定义如下:

注解 (Annotation),也叫元数据。一种代码级别的说明。它是 JDK1.5 及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。 ——摘自百度百科

上面的说明虽然严谨,但比较难懂。笔者认为《秒懂,Java 注解 (Annotation)你可以这样学》一文中,作者 frank909 大佬的解释十分亲民:可以完全将注解当做生活中我们对人对物贴的标签。

拿笔者最喜欢的一部动画电影来打个比方吧:《Zootopia》。《Zootopia》整个电影将动物们拟人化,性格各异。不管是兔子,狐狸,羚羊,豹子等等,每个动物都有一张固有标签:兔子乖巧,狐狸狡黠,羚羊温顺,豹子凶猛。 但它们又有着自己真实的性格:想当警察的兔子,狡黠却不失善良的狐狸,披着狼皮的腹黑羚羊,吃着甜甜圈有少女心的豹子。

《Zootopia》这个电影的内核是在讲,我们要试图冲破外界对自己所贴的标签的限制。但在这里笔者要稍微的当一下杠精,吹一下标签的作用:贴标签是较为精准的了解一个事物的最高效率方法。疯狂动物城中的动物们,外界对他们的第一印象,往往都是直接引用了该物种性格的固有标签。同样的在 Java 中,注解的作用就是告诉开发人员,被注解的内容是用来做什么的,换句话说,注解就是 Java 代码的标签。 在 Java 中,给代码贴合适的标签是很重要的,它很大程度的提高了效率。虽然写代码的时候开发人员也可以致敬《Zootopia》主旨,尝试突破标签的限制(比如给实现了 @Controller 功能的代码加了 @Service 注解),但笔者不保证写下这样代码开发人员的后续人身安全,太睿智的人肯定是要被针对的……

1.2 注解的作用 能够读懂别人写的代码(尤其是框架相关的代码);实现替代配置文件的功能。比如可能原本需要很多配置文件以及很多逻辑才能实现的内容,如果使用合理的注解,就可以使用一个或多个注解来实现相同的功能。这样就使得代码更加清晰和整洁;编译时进行格式检查。 如 @Override 注解放在方法前,如果该方法不是覆盖了某个超类方法,编译的时候编译器就能检查出来。装逼。 做技术的怎么可以没有一点用技术吹牛逼的心理呢?如果会在合适的地方恰好的使用注解或者自定义注解的话,老板肯定会双手送你 666 的。当然笔者现在只是初学而已,距离用技术吹牛逼的道路还远。 1.3 注解的原理

注解本质是一个继承了 Annotation 的特殊接口,其具体实现类是 Java 运行时生成的动态代理类。而我们通过反射获取注解时,返回的是 Java 运行时生成的动态代理对象 $Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用 AnnotationInvocationHandler 的 invoke 方法。该方法会从 memberValues 这个 Map 中索引出对应的值。而 memberValues 的来源是 Java 常量池。 ——摘自《注解Annotation实现原理与自定义注解例子》

这里涉及的内容比较深入,笔者目前不能理解。先贴上来,以后慢慢来吧。

二. 元注解

元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。或者可以理解为:元注解也是一张标签,但是它是一张特殊的标签,它的作用和目的就是给其他普通的标签进行解释说明的。

基本的元标签有 @Retention, @Documented, @Target, @Inherited 四种(后来到了 Java 8 又加入了 @Repeatable)。

2.1 @Retention

@Retention 定义了该注解的生命周期。当 @Retention 应用到一个注解上的时候,作用就是说明这个注解的存活时间。

RetentionPolicy.SOURCE: 注解只在源码阶段保留,在编译器完整编译之后,它将被丢弃忽视; 例:@Override, @SuppressWarningsRetentionPolicy.CLASS: 注解只被保留到编译进行的时候,它并不会被加载到 JVM 中;RetentionPolicy.RUNTIME: 注解可以保留到程序运行的时候,它会被加载进入到 JVM 中,所以在程序运行时可以获取到它们;笔者接触到大部分的注解都是 RUNTIME 的生命周期。

以 SpringMVC 中的 @Service 的源码为例:

package org.springframework.stereotype; 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.TYPE}) @Retention(RetentionPolicy.RUNTIME) @Documented @Component public @interface Service { String value() default ""; }

这里 @Service 拥有 @Retention(RetentionPolicy.RUNTIME) 注解,所以在程序运行时可以捕获到它们。

2.2 @Target

@Target 表示该注解用于什么地方,可以理解为:当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。可以使用的 ElementType 参数:

ElementType.CONSTRUCTOR: 对构造方法进行注解;ElementType.ANNOTATION_TYPE: 对注解进行注解;ElementType.FIELD: 对属性、成员变量、成员对象(包括 enum 实例)进行注解;ElementType.LOCAL_VARIABLE: 对局部变量进行注解;ElementType.METHOD: 对方法进行注解;ElementType.PACKAGE: 对包进行注解;ElementType.PARAMETER: 对描述参数进行注解;ElementType.TYPE: 对类、接口、枚举进行注解;

如上面的 @Service 所示,@Service 的 @Target 注解值为 ElementType.TYPE,即 @Service 只能用于修饰类。

2.3 @Documented

@Documented 是一个简单的标记注解,表示是否将注解信息添加在 Java 文档,即 Javadoc 中。

2.4 @Inherited

Inherited 是指继承,@Inherited 定义了一个注释与子类的关系。如果一个超类带有 @Inherited 注解,那么对于该超类,它的子类如果没有被任何注解应用的话,那么这个子类就继承了超类的注解。

用《秒懂,Java 注解 (Annotation)你可以这样学》一文中的例程与解释来说明:

@Inherited @Retention(RetentionPolicy.RUNTIME) @interface Test {} @Test public class A {} public class B extends A {}

注解 Test 被 @Inherited 修饰,之后类 A 被 Test 注解,类 B 继承 A,类 B 也拥有 Test 这个注解。可以这样理解: 老子非常有钱,所以人们给他贴了一张标签叫做富豪。 老子的儿子长大后,只要没有和老子断绝父子关系,虽然别人没有给他贴标签,但是他自然也是富豪。 老子的孙子长大了,自然也是富豪。 这就是人们口中戏称的富一代,富二代,富三代。虽然叫法不同,好像好多个标签,但其实事情的本质也就是他们有一张共同的标签,也就是老子身上的那张富豪的标签。

2.5 @Repeatable

@Repeatable 是 Java 8 中加入的,是指可重复的意思。通常使用 @Repeatable 的时候指注解的值可以同时取多个。依旧用《秒懂,Java 注解 (Annotation)你可以这样学》一文中的例程与解释来说明:一个人既是程序员,又是产品经理,同时也是画家。

@interface Persons { Person[] value(); } @Repeatable(Persons.class) @interface Person { String role default ""; } @Person(role="artist") @Person(role="coder") @Person(role="PM") public class SuperMan { ... }

上面的代码通过 @Repeatable 定义了 Person,而 @Repeatable 后面括号的类相当于一个容器注解。容器注解就是用来存放其它注解的地方,它本身也是一个注解。

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


【本文地址】

公司简介

联系我们

今日新闻

    推荐新闻

    专题文章
      CopyRight 2018-2019 实验室设备网 版权所有