java注解(1)

参考:

  1. 秒懂,Java 注解 (Annotation)你可以这样学
  2. 疯狂java讲义

1. 定义

classsinterface 一样,注解也属于一种类型。
注解通过 @interface 关键字进行定义。

public @interface TestAnnotation {
}

2. 语法

默认情况下,Annotation可用于修饰任何程序元素,包括接口、类、方法等。

Annotation成员变量以方法形式定义

Annotation中的成员变量以无形参的方法形式来声明。定义了几个成员变量,在使用时必须给值。

public @interface MyTag {
    String name();
    int age();
}

有个默认值,在使用时可以不给值。

public @interface MyTag {
    String name() default "hobe";
    int age() default 18;
}

Annotation

jdk除了java.lang下的5个基本Annotation:

  • @Override(限定重写)
  • @Deprecated(标记过时)
  • @SuppressWarnings(抑制警告)
  • @SafeVarargs(java7)
  • @functionalInterface(java8)

之外,java.lang.annotation包下提供了6个Meta Annotation(元Annotation),其中5个都用于修饰其他Annotation。主要几个如下:

1 @Retention

只能修饰Annotation定义,指定修饰多长时间,其源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
    /**
     * Returns the retention policy.
     * @return the retention policy
     */
    RetentionPolicy value();
}

其中只有一个成员变量。

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
}

SOURCE:用于检查代码,编译时丢掉。(主要看IDE是否报错)
CLASS:(默认)。编译后也会记录在class文件中。运行时,JVM不可获取Annotation信息,不可反射获取。
RUNTIME:(通常会使用)。编译后也会记录在class文件中。运行时,JVM可获取Annotation信息,可反射获取

使用示例

@Retention(RetentionPolicy.RUNTIME)
public @interface MyTag {
    ...
}

或:

@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyTag {
    ...
}

说明

当Annotation成员变量名为 value时,只需为value指定值时, 可以在括号里直接写出value的值,无需name=value的形式

2 @Target

只能修饰Annotation定义。指定哪些程序单元可以使用,源码:

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    /**
     * Returns an array of the kinds of elements an annotation type
     * can be applied to.
     * @return an array of the kinds of elements an annotation type
     * can be applied to
     */
    ElementType[] value();
}
public enum ElementType {
    /** Class, interface (including annotation type), or enum declaration */
    TYPE,

    /** Field declaration (includes enum constants) */
    FIELD,

    /** Method declaration */
    METHOD,

    /** Formal parameter declaration */
    PARAMETER,

    /** Constructor declaration */
    CONSTRUCTOR,

    /** Local variable declaration */
    LOCAL_VARIABLE,

    /** Annotation type declaration */
    ANNOTATION_TYPE,

    /** Package declaration */
    PACKAGE,

    /**
     * Type parameter declaration
     *
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     *
     * @since 1.8
     */
    TYPE_USE
}

如只能修饰成员变量则使用:

@Target({ElementType.FIELD})

3 @Documented

被该Annotation修饰的类将会被javadoc工具提取成文档。

4 @Inherited

被@Inherited修饰的注解,用于父类时,子类自动会加该注解。

System.out.println(ChildClass.class.isAnnotationPresent(MyTag.class));

true

3. 自定义Annotation

分类:标记Annotation元数据Annotation

根据Annotation是否包含成员变量,将其分为两类:

  • 标记Annotation:没有定义成员变量,尽利用自身是否存在与否来提供信息。如@Test,@Override
  • 元数据Annotation:包含成员变量。

注意的一种情况是一个注解没有任何属性。比如

public @interface Perform {}

那么在应用这个注解的时候,括号都可以省略。

@Perform
public void testMethod(){}

示例

@Target({ElementType.FIELD})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyTag {
    String name() default "hobe"; //字符串
    int age() default 18;  //int
    String[] likes(); // 数组
    Sex sex(); //枚举
}

反射提取Annotation信息

使用Annotation修饰了类、方法、成员变量等成员之后,这些Annotation并不会自己生效。必须由开发者提取信息并处理。
java.lang.reflect增加了读取运行时Annotation的能力。如:

  • getAnnotation()
  • getAnnotations()
  • isAnnotationPresent()
  • getAnnotationsByType()
  • ...

如获取Mytag注解中info方法上的所有注解,则:

 Class.forName("MyTag").getMethods("info").getAnnotations()

使用示例

  • 注解类:
@Target({ElementType.FIELD,ElementType.TYPE})
@Retention(value = RetentionPolicy.RUNTIME)
public @interface MyTag {
    String name() default "hobe"; //字符串
    int age() default 18;  //int
    String[] likes(); // 数组
    Sex sex() default Sex.BOY; //枚举
}
public enum Sex {
    BOY,GIRL
}
  • 工具类(这里工具类和被注解类放在一起了)
@MyTag(likes = {"code","ball"})
public class Demo {
    private String name;
    private Integer age;
    private String[] likes;
    private Sex sex;

    public static void main(String[] args) {
        Demo demo = new Demo();
        /** 仅仅注解,并不能将值赋给Demo的字段 */
        System.out.println(demo);

        boolean hasAnnotation = Demo.class.isAnnotationPresent(MyTag.class);
        if (hasAnnotation){
            MyTag myTag = Demo.class.getAnnotation(MyTag.class);
            System.out.println(myTag.name());
            System.out.println(myTag.likes());
            System.out.println(myTag.sex());
            System.out.println(myTag.age());
        }
    }
    ...
}

结果:

Demo{name='null', age=null, likes=null, sex=null}
hobe
[Ljava.lang.String;@4617c264
BOY
18

参考:

  1. 秒懂,Java 注解 (Annotation)你可以这样学
  2. 疯狂java讲义

你可能感兴趣的:(annotation,注解)