注解这东西,已经在我们的编程生活中习以为常了。覆盖一个父类的方法,套用Spring、Mybatis中的编程套路,编写JUnit测试函数等等。你会发现,作为一个Java Coder,你无时无刻不在接触它们。
但是如何编写一个属于自己的注解,或是希望能够看懂那些NB框架的源代码,都有必要让你我去掌握编写自定义注解的方法。
本系列开始,我将和博客的观众们一起学习java注解的开发。
注解分类(按照来源来分)
jdk中的注解:
@Override 重写父类的方法。如果父类没有该方法则编译报错
@Override public String toString() { return "Member [id=" + id + ", familyName=" + familyName + ", givenName=" + givenName + ", salary=" + salary + "]"; }
@Deprecated 以前的定义的类或方法,大家正用得high,你却觉得好像这样设计并不好,于是加入了新的类或方法来代替它们。但是,这样做,以前的小伙伴们又要抱怨了,"你这个前后版本不兼容"云云,所以我们需要用一个注解指明"存在但已过时,可用但不推荐”,这就是@Deprecated。
比如,由于现在的猫都不捉老鼠了,所以,下面这个方法,我决定废弃。但是以前已经有太多围绕猫的方法调用了,所以我加入了注解@Deprecated。IDE中的删除线就是醒目的标识。
哎呀呀,好像调用注解了@Deprecated的方法之后,出现了warning!
HappyBKs我是个代码洁癖,一定要把这个警告去掉。
类似的我们编写代码的过程中,往往不可避免了会出现一些警告,有些我们可以根据好的范式、好的习惯、好的经验把这些代码重新修改消除警告。但是有时一些场景,似乎要求我们包容他们。怎么办呢?这时候,可以用@SuppressWarnings注解,消除相应警告类型。
比如上面的调用废弃方法产生的警告,我们可以改成这样:
现在警告没有了!: )
第三方注解:
如果你是一个java框架的达人,一定知道spring额@Autowired自动创配,以及@Service和@Repository;也一定会用Mybatis的@InsertProvider,@UpdateProvider,@Option。
作为用框架的人,少不了和这些第三方注解打交道。这里就不介绍框架了。
自定义的注解:
如果我们想读懂别人的代码、自己尝试着写一下框架、装装B格,那么自己写一个注解是必不可少的。这也是本系列文章的目标!!
其实要有一类比较特殊的注解,不知道该把它按照哪个范畴进行划分,那就是元注解。
元注解:指的是注解的注解。就像元数据是描述数据的数据一样。具体的我会单独在一篇文章中介绍。
注解的运行机制、作用域、继承性等:
我门对注解进行分类,还可以按照运行机制分类
注解的运行机制:
按照这个运行机制的不同,我们可以将注解分成三类:
源码注解: 注解只在源码中存在,编译成.class文件就不存在了。
编译时注解:注解在.class文件里面存在。当然在.class文件中存在,在源码当中当然也是存在的。刚才说的3个jdk自带的注解@Deprecated 、@SuppressWarnings、@Override都属于编译时注解。也正因为如此,当你@Override了父类不存在的方法,编译时编译器会报错;调用@Deprecated的方法,编译器会警告。IDE才能在编辑代码时实时提示错误。
运行时注解:在运行阶段还起作用,甚至会影响运行逻辑的注解。
如何指定一个注解的运行机制:(即影响的时间点)
我们在定义一个注解时,还需要指明它是源码注解、编译时注解还是运行时注解。这里也需要用到一个枚举:
/* * Copyright (c) 2003, 2004, Oracle and/or its affiliates. All rights reserved. * ORACLE PROPRIETARY/CONFIDENTIAL. Use is subject to license terms. */ package java.lang.annotation; /** * Annotation retention policy. The constants of this enumerated type * describe the various policies for retaining annotations. They are used * in conjunction with the {@link Retention} meta-annotation type to specify * how long annotations are to be retained. * * @author Joshua Bloch * @since 1.5 */ public enum RetentionPolicy { /** * Annotations are to be discarded by the compiler. */ SOURCE, /** * Annotations are to be recorded in the class file by the compiler * but need not be retained by the VM at run time. This is the default * behavior. */ CLASS, /** * Annotations are to be recorded in the class file by the compiler and * retained by the VM at run time, so they may be read reflectively. * * @see java.lang.reflect.AnnotatedElement */ RUNTIME }
注解的作用域:
注解的作用域指的是一个注解修饰的是什么语法单元。注解标识的是一个类,一个方法,一个域,一个构造器等等。这里在指定注解的作用域时会用到一个枚举来指定作用域的类型,这里我把jdk的源码列出:
package java.lang.annotation; /** * A program element type. The constants of this enumerated type * provide a simple classification of the declared elements in a * Java program. * * <p>These constants are used with the {@link Target} meta-annotation type * to specify where it is legal to use an annotation type. * * @author Joshua Bloch * @since 1.5 */ public enum ElementType { /** Class, interface (including annotation type), or enum declaration */ TYPE, /** Field declaration (includes enum constants) */ FIELD, /** Method declaration */ METHOD, /** Parameter declaration */ PARAMETER, /** Constructor declaration */ CONSTRUCTOR, /** Local variable declaration */ LOCAL_VARIABLE, /** Annotation type declaration */ ANNOTATION_TYPE, /** Package declaration */ PACKAGE }
注解的继承性:
规定了一个注解在标注了一个类、接口或方法等之后是否会在所在类的子类中生效。这个我会在本系列后面的文章中单独写一篇介绍。
注解输出到文档:
这个就是@Docmented注解,指定注解是否被输出到java文档中。
Documented 注解表明这个注解应该被 javadoc工具记录. 默认情况下,javadoc是不包括注解的. 但如果声明注解时指定了 @Documented,则它会被 javadoc 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中。
具体如何写一个自己的注解。放到下一篇文章中写吧。