版权声明:本文为博主原创文章,未经博主允许不得转载。
参考网址:
什么是注解?严谨的来说,注解提供了一种安全的类似注释的机制,用来将任何的信息或元数据(metadata)与程序元素(类、方法、成员变量等)进行关联。为程序的元素(类、方法、成员变量)加上更直观的说明,这些说明信息是与程序的业务逻辑无关,并且供指定的工具或框架使用。Annontation像一种修饰符一样,应用于包、类型、构造方法、方法、成员变量、参数及本地变量的声明语句中。
Java 注解是附加在代码中的一些元信息,用于一些工具在编译、运行时进行解析和使用,起到说明、配置的功能。注解不会也不能影响代码的实际逻辑,仅仅起到辅助性的作用。注解包含在 java.lang.annotation 包中。
具体定义如下:
注解 (Annotation),也叫元数据。一种代码级别的说明。它是 JDK1.5 及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。 ——摘自百度百科
上面的说明虽然严谨,但比较难懂。笔者认为一文中,作者 frank909 大佬的解释十分亲民:可以完全将注解当做生活中我们对人对物贴的标签。
拿笔者最喜欢的一部动画电影来打个比方吧:《Zootopia》。《Zootopia》整个电影将动物们拟人化,性格各异。不管是兔子,狐狸,羚羊,豹子等等,每个动物都有一张固有标签:兔子乖巧,狐狸狡黠,羚羊温顺,豹子凶猛。
但它们又有着自己真实的性格:想当警察的兔子,狡黠却不失善良的狐狸,披着狼皮的腹黑羚羊,吃着甜甜圈有少女心的豹子。
《Zootopia》这个电影的内核是在讲,我们要试图冲破外界对自己所贴的标签的限制。但在这里笔者要稍微的当一下杠精,吹一下标签的作用:贴标签是较为精准的了解一个事物的最高效率方法。疯狂动物城中的动物们,外界对他们的第一印象,往往都是直接引用了该物种性格的固有标签。同样的在 Java 中,注解的作用就是告诉开发人员,被注解的内容是用来做什么的,换句话说,注解就是 Java 代码的标签。
在 Java 中,给代码贴合适的标签是很重要的,它很大程度的提高了效率。虽然写代码的时候开发人员也可以致敬《Zootopia》主旨,尝试突破标签的限制(比如给实现了 @Controller 功能的代码加了 @Service 注解),但笔者不保证写下这样代码开发人员的后续人身安全,太睿智的人肯定是要被针对的……
注解本质是一个继承了 Annotation 的特殊接口,其具体实现类是 Java 运行时生成的动态代理类。而我们通过反射获取注解时,返回的是 Java 运行时生成的动态代理对象 $Proxy1。通过代理对象调用自定义注解(接口)的方法,会最终调用 AnnotationInvocationHandler 的 invoke 方法。该方法会从 memberValues 这个 Map 中索引出对应的值。而 memberValues 的来源是 Java 常量池。 ——摘自
这里涉及的内容比较深入,笔者目前不能理解。先贴上来,以后慢慢来吧。
元注解是可以注解到注解上的注解,或者说元注解是一种基本注解,但是它能够应用到其它的注解上面。或者可以理解为:元注解也是一张标签,但是它是一张特殊的标签,它的作用和目的就是给其他普通的标签进行解释说明的。
基本的元标签有 @Retention, @Documented, @Target, @Inherited 四种(后来到了 Java 8 又加入了 @Repeatable)。
@Retention 定义了该注解的生命周期。当 @Retention 应用到一个注解上的时候,作用就是说明这个注解的存活时间。
以 SpringMVC 中的 @Service 的源码为例:
这里 @Service 拥有 @Retention(RetentionPolicy.RUNTIME) 注解,所以在程序运行时可以捕获到它们。
@Target 表示该注解用于什么地方,可以理解为:当一个注解被 @Target 注解时,这个注解就被限定了运用的场景。可以使用的 ElementType 参数:
如上面的 @Service 所示,@Service 的 @Target 注解值为 ElementType.TYPE,即 @Service 只能用于修饰类。
@Documented 是一个简单的标记注解,表示是否将注解信息添加在 Java 文档,即 Javadoc 中。
Inherited 是指继承,@Inherited 定义了一个注释与子类的关系。如果一个超类带有 @Inherited 注解,那么对于该超类,它的子类如果没有被任何注解应用的话,那么这个子类就继承了超类的注解。
用一文中的例程与解释来说明:
注解 Test 被 @Inherited 修饰,之后类 A 被 Test 注解,类 B 继承 A,类 B 也拥有 Test 这个注解。可以这样理解: 老子非常有钱,所以人们给他贴了一张标签叫做富豪。 老子的儿子长大后,只要没有和老子断绝父子关系,虽然别人没有给他贴标签,但是他自然也是富豪。 老子的孙子长大了,自然也是富豪。 这就是人们口中戏称的富一代,富二代,富三代。虽然叫法不同,好像好多个标签,但其实事情的本质也就是他们有一张共同的标签,也就是老子身上的那张富豪的标签。
@Repeatable 是 Java 8 中加入的,是指可重复的意思。通常使用 @Repeatable 的时候指注解的值可以同时取多个。依旧用一文中的例程与解释来说明:一个人既是程序员,又是产品经理,同时也是画家。
上面的代码通过 @Repeatable 定义了 Person,而 @Repeatable 后面括号的类相当于一个容器注解。容器注解就是用来存放其它注解的地方,它本身也是一个注解。
上面是 @Repeatable 的源码。按照规定,如果使前面的 Persons 里面可以重复调用某个注解,则 Persons 必须有一个 value 的属性,且属性类型必须为被 @Repeatable 注解的 Person。
注解的属性也叫做成员变量。注解只有成员变量,没有方法。注解的成员变量在注解的定义中以无形参的方法形式来声明,其方法名定义了该成员变量的名字,其返回值定义了该成员变量的类型。以下面的例程为例:
上面假设定义了一个名为 @Coder 的注解,该注解有 id, name, language, company 三个属性。使用的时候,我们应该对其赋值。赋值的方式类似于 key=”value” 的方式进行,属性之间用 “,” 隔开:
此外,注解可以有默认值,需要用 default 关键字指定。例如上例:
如果:
由于在 @Coder 注解中设置了默认值,所以就不需要再 @Coder 后面的括号里进行赋值了。
此外,如果注解内只有一个名为 value 的属性时,应用该属性时可以将值直接写到括号内,不用写 value = “…”。例如:
那么下面两种声明是相同的:
Java 中自带且常用的几种注解有 @Override, @Deprecated, @SuppresWarninngs, @SafeVarargs。
@Override 是一个标记类型注解,用于提示子类要复写父类中被 @Override 修饰的方法,它说明了被标注的方法重载了父类的方法,起到了断言的作用。如果我们使用了这种注解在一个没有覆盖父类方法的方法时,java编译器将以一个编译错误来警示。
@Deprecated 也是一个标记类型注解,用于标记过时的元素。比如如果开发人员正在调用一个过时的方法、类或成员变量时,可以用该注解进行标注。
@SuppressWarnings 并不是一个标记类型注解,它可以阻止警告的提示。它有一个类型为 String[] 的成员,其值为被禁止的警告名。
@SafeVarargs 是一个参数安全类型注解。它的目的是提醒开发人员,不要用参数做一些不安全的操作。它的存在会阻止编译器产生 unchecked 的警告。例如对于可变长度参数,如果和泛型一起使用,会产生比较多的编译器警告。如下面的方法:
如果参数传递的是不可具体化的类型(类似于 List 的泛型类型),每调用一次该方法,都会产生警告信息。如果希望禁止这个警告信息,可以使用 @SuppressWarnings(“unchecked”) 注解进行声明。同时在 Java 7 版本之后的 @SafeVarargs 注解针对 “unchecked” 警告进行了屏蔽,我们也可以用 @SafeVarargs 获得 @SuppressWarnings(“unchecked”) 同样的效果。
此处参考的原理介绍和水果例程。
自定义注解类编写的规则:
以水果与水果供应商为例:
水果名称注解 FruitName.java:
水果颜色注解 FruitColor.java:
水果供应者注解 FruitProvider.java:
注解处理器 FruitInfoUtil.java:
苹果 Apple.java:
测试输出水果信息 FruitTestAnnotation:
运行后的测试结果为:
水果名称:Apple 水果颜色:RED 供应商编号:1 供应商名称:陕西红富士集团 供应商地址:陕西省西安市延安路89号红富士大厦undefined
这段时间虽然在 SpringMVC 中用注解用的飞起,各种 @RequestMapping, @Service, @Controller 等注解信手拈来,但还是不了解它的运作原理到底是什么样的。尤其是在框架中,大量运用到了注解与反射操作,所以以后也会认真了解一下如 Spring 框架中注解的运行原理,想必这无论是对理解框架,还是对理解注解本身,都会有很大的帮助。
版权声明:
本文来源网络,所有图片文章版权属于原作者,如有侵权,联系删除。
本文网址:https://www.mushiming.com/mjsbk/6584.html