注解这东西,已经在我们的编程生活中习以为常了。覆盖一个父类的方法,套用Spring、Mybatis中的编程套路,编写JUnit测试函数等等。你会发现,作为一个Java Coder,你无时无刻不在接触它们。

但是如何编写一个属于自己的注解,或是希望能够看懂那些NB框架的源代码,都有必要让你我去掌握编写自定义注解的方法。

本系列开始,我将和博客的观众们一起学习java注解的开发。


注解分类(按照来源来分)

jdk中的注解:

@Override 重写父类的方法。如果父类没有该方法则编译报错

@Override
	public String toString() {
		return "Member [id=" + id + ", familyName=" + familyName
				+ ", givenName=" + givenName + ", salary=" + salary + "]";
	}
@Override
	public String toString() {
		return "Member [id=" + id + ", familyName=" + familyName
				+ ", givenName=" + givenName + ", salary=" + salary + "]";
	}

@Deprecated 以前的定义的类或方法,大家正用得high,你却觉得好像这样设计并不好,于是加入了新的类或方法来代替它们。但是,这样做,以前的小伙伴们又要抱怨了,"你这个前后版本不兼容"云云,所以我们需要用一个注解指明"存在但已过时,可用但不推荐”,这就是@Deprecated。

比如,由于现在的猫都不捉老鼠了,所以,下面这个方法,我决定废弃。但是以前已经有太多围绕猫的方法调用了,所以我加入了注解@Deprecated。IDE中的删除线就是醒目的标识。


Java的注解在底层是如何实现对应的功能的 java中注解的作用_ide

Java的注解在底层是如何实现对应的功能的 java中注解的作用_ide

Java的注解在底层是如何实现对应的功能的 java中注解的作用_作用域_03

哎呀呀,好像调用注解了@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
}
/*
 * 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
}
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 之类的工具处理, 所以注解类型信息也会被包括在生成的文档中。


具体如何写一个自己的注解。放到下一篇文章中写吧。