1. 注解入门

Annotation 是从 JDK5.0 开始引入的新技术

  • Annotation 的作用
    注解不是程序, 可以对程序作出解释
    注解可以被其他程序 (比如编译器) 读取

  • Annotation 的格式
    注解是以 "@注释名" 在代码中存在的, 还可以添加一些参数信息
    如:@SuppressWarning(value="unchecked")

  • Annotation 在哪里使用
    注解可以附加在 package,class,method,field 等上面, 相当于给他们添加了额外的辅助信息, 我们可以通过反射机制编程实现对这些元数据的访问

示例:

public class AnnotationDemo {

    @Override
    public String toString() {
        return super.toString();
    }

}

@Override 表示重写了父类的方法, 如果父类中不存在此方法就会报错

让我们看看 Override 的源码:

package java.lang;

import java.lang.annotation.*;

/**
 * Indicates that a method declaration is intended to override a
 * method declaration in a supertype. If a method is annotated with
 * this annotation type compilers are required to generate an error
 * message unless at least one of the following conditions hold:
 *
 * <ul><li>
 * The method does override or implement a method declared in a
 * supertype.
 * </li><li>
 * The method has a signature that is override-equivalent to that of
 * any public method declared in {@linkplain Object}.
 * </li></ul>
 *
 * @author  Peter von der Ah&eacute;
 * @author  Joshua Bloch
 * @jls 9.6.1.4 @Override
 * @since 1.5
 */
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

注解也是一个类,@interface 是声明注解的关键字

2. 内置注解

  • @Override
    定义在 java.lang.Override 中, 此注释只适用于修饰方法, 表示一个方法声明打算重写父类的另一个方法

  • Deprecated
    定义在 java.lang.Deprecated 中, 此注释只适用于修饰方法, 属性, 类, 表示不鼓励程序员使用这样的元素, 通常是因为它很危险或存在更好的选择

在常用的 Date 类中有很多被 Deprecated 修饰的方法:

@Deprecated
public Date(int year, int month, int day) {
    super(year, month, day);
}

我们再看看 Deprecated 的源码:

package java.lang;

import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;

/**
 * A program element annotated &#64;Deprecated is one that programmers
 * are discouraged from using, typically because it is dangerous,
 * or because a better alternative exists.  Compilers warn when a
 * deprecated program element is used or overridden in non-deprecated code.
 *
 * @author  Neal Gafter
 * @since 1.5
 * @jls 9.6.3.6 @Deprecated
 */
@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

当你使用一个被 @Deprecated 修饰的方法时编译器会报一个警告, 不建议使不代表不能使

  • @SuppressWarnings
    定义在 java.lang.SuppressWarnings 中, 用来抑制编译时的警告信息
    与前两个注解有所不同, 你需要添加一个参数才能正确使用, 这些参数的值已经定义好了, 我们选择性的使用就好了, 参数如下:
    参数 说明
    deprecation  使用了过时的类或方法
    unchecked  执行了未检查的转换时的警告, 如使用集合时未指定泛型 
    fallthrough  当在 switch 语句使用时发生 case 穿透
    path  在类路径, 源文件路径等中有不存在的路径警告
    serial  当在可序列化的类上缺少 serialVersionUID 定义时的警告
    finally  任何 finally 子句不能完成时的警告
    all  关于以上所有情况的警告

使用一个:@SuppressWarnings("all")
使用多个:@SuppressWarnings(value={"unchecked","deprecation"})

当我们写的代码有警告但你不想理它们的时候你可以有 @SuppressWarnings 来抑制警告:

@SuppressWarnings("all")
public static void main(String[] args) {

    List list = new ArrayList();
}

让我们看看源码:

import java.lang.annotation.*;
import static java.lang.annotation.ElementType.*;

/**
 * Indicates that the named compiler warnings should be suppressed in the
 * annotated element (and in all program elements contained in the annotated
 * element).  Note that the set of warnings suppressed in a given element is
 * a superset of the warnings suppressed in all containing elements.  For
 * example, if you annotate a class to suppress one warning and annotate a
 * method to suppress another, both warnings will be suppressed in the method.
 *
 * <p>As a matter of style, programmers should always use this annotation
 * on the most deeply nested element where it is effective.  If you want to
 * suppress a warning in a particular method, you should annotate that
 * method rather than its class.
 *
 * @author Josh Bloch
 * @since 1.5
 * @jls 4.8 Raw Types
 * @jls 4.12.2 Variables of Reference Type
 * @jls 5.1.9 Unchecked Conversion
 * @jls 5.5.2 Checked Casts and Unchecked Casts
 * @jls 9.6.3.5 @SuppressWarnings
 */
@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    /**
     * The set of warnings that are to be suppressed by the compiler in the
     * annotated element.  Duplicate names are permitted.  The second and
     * successive occurrences of a name are ignored.  The presence of
     * unrecognized warning names is <i>not</i> an error: Compilers must
     * ignore any warning names they do not recognize.  They are, however,
     * free to emit a warning if an annotation contains an unrecognized
     * warning name.
     *
     * <p> The string {@code "unchecked"} is used to suppress
     * unchecked warnings. Compiler vendors should document the
     * additional warning names they support in conjunction with this
     * annotation type. They are encouraged to cooperate to ensure
     * that the same names work across multiple compilers.
     * @return the set of warnings to be suppressed
     */
    String[] value();
}

value 为参数名, String[ ] 为参数的类型

3. 自定义注解, 元注解

使用 @interface 自定义注解, 自动继承了 java.lang.annotation.Annotation 接口

要点

@interface 用来声明一个注解, 格式为:

  • public @interface 注解名 {定义体}

    其中的每一个方法实际是声明了一个配置参数

  • 方法的名称就是参数的名称

  • 返回值类型就是参数的类型 (返回值类型只能是基本类型, Class,String,enum)

  • 可以通过 default 来声明参数的默认值

  • 如果只有一个参数成员, 一般参数名为 value

  • 注解元素必须要有值. 我们定义注解元素是, 经常使用空字符串, 0 作为默认值, 也经常使用负数 (比如:-1) 表示不存在的含义

定义:

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

@Target(value={ElementType.METHOD,ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {

    String studentName() default "";
    int age() default 0;
    int id() default -1;

    String[] schools() default {"清华大学","北京大学"};
}

使用:

@MyAnnotation(age=19,studentName="Matrix42",id=100,
schools={"北京大学","清华大学"})
public class Demo {

}

元注解

  • 元注解的作用就是负责注解其他注解, Java 定义了 4 个标准的 meta-annotation 类型, 它们被用来提供对其他 annotation 类型作说明

  • 这些类型和它们所支持的类在 java.lang.annotation 包中可以找到 (后两个不常用)

    - @Target
    - @Retention
    - @Documented
    - @Inherited

  • @Target

用来描述注解使用范围 (即: 被描述的注解可以用在什么地方)

所修饰范围 取值 ElementType
package 包  PACKAGE
类, 接口, 枚举, Annotation 类型  TYPE
类型成员 (方法, 构造方法, 成员变量, 枚举值)  CONSTRUCTOR: 用来描述构造器
FIELD: 用来描述域
METHOD: 用于描述方法
方法参数和本地变量  LOCAL_VERIABLE: 用于描述局部变量
PARAMETER: 用于描述参数

- @Target(value=ElementType.TYPE)

  • @Retention

表示需要在什么级别保存该注释信息, 用于描述注解的生命周期

取值 RetentionPolicy 作用
SOURCE  在源文件中有效 (即源文件保留)
CLASS  在 class 文件中有效 (即 class 保留)
RUNTIME  在运行时有效 (即运行时保留)
为 Runtime 可以被反射机制读取
方法参数和本地变量  LOCAL_VERIABLE: 用于描述局部变量
PARAMETER: 用于描述参数

如果只是使用注解做一些标识是没有什么意义的, 只有在通过其他程序处理这些注解时才有意义