我所理解的JDK注解

1,什么是注解
  从宏观上讲:注解能够理解为是一个标签,做用在package、class、constructor、field、method之上,代表该元素具备的一类信息。
  从代码上讲:@Xxx就是一个注解,使用@interface做用在class名上能够代表该class文件是一个注解类。java

2,注解的表示
java.lang.annotation.Annotation是一个特殊的接口ide

package java.lang.annotation;
public interface Annotation {
    boolean equals(Object obj);
    int hashCode();
    String toString();
    Class<? extends Annotation> annotationType();
}

  这4个接口能够认为是JVM运行须要使用的,由编译器在编译期完成,开发人员不须要关注。
  使用@interface做用在class名上后即表示该class实现了Annatation接口,具体的实现过程有编译器完成。工具

3,注解的详细表示
先来一个普通的自定义注解:ui

@Documented
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface MyAnnotation {
    String value();
    String name() default "Lily";
}
  • @Documented、@Target、@Retention是JDK自带的一些元注解。
  • value()是一个注解类的默认方法,使用@MyAnnotation("abc")时在括号内不须要指定value,就表示value="abc"
  • default表示默认值,@MyAnnotation("abc", name="Lucy")则表示value="abc",name="Lucy"。若是没有指定name,则name="Lily"
  • 若是没有默认值时,使用注解时必须指定值,不然报错。好比@MyAnnotation()就会提示错误,须要指定value

4,什么是元注解
  元注解也是注解,使用来修饰注解的注解,代表该注解的一些基本信息。JDK自带的元注解有: @Inherited、@Retention、@Target、@Repeatable、@Deprecated、@Documented、@SuppressWarnings、@Override等this

@Deprecated用来表示该元素已通过时,再也不推荐使用:code

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(value={CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE})
public @interface Deprecated {
}

@Documented用来生成Java doc注释:对象

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Documented {
}

@Inherited用来表示被该注解修饰的注解具备继承性。即若是父类有此注解则子类也有此注解继承

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Inherited {
}

@Retention用来表示该注解修饰的注解的做用域。接口

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

@Repeatable表示一个类上能够有多个被该注解修饰的注解,JDK1.8新增作用域

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Repeatable {
    Class<? extends Annotation> value();
}

@Target表示该注解的能够修饰哪些元素

@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Target {
    ElementType[] value();
}

@SuppressWarnings用来表示警告

@Target({TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE})
@Retention(RetentionPolicy.SOURCE)
public @interface SuppressWarnings {
    String[] value();
}

@Override用来表示方法重写

@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}

@Retention中须要的RetentionPolicy 的源码:

package java.lang.annotation;
public enum RetentionPolicy {
    SOURCE, // 存在于源码中,编译后的class文件中不包含该注解信息。
    CLASS, // 该注解会存在于编译后的class文件中,可是JVM运行时不读取该信息。是默认的行为
    RUNTIME // 该注解会存在于编译后的class文件中,在JVM运行时会读取该信息,使用反射能够获取到
}

@Target中须要的ElementType的源码:

package java.lang.annotation;
public enum ElementType {
    TYPE, // 类型信息,能够是Class、interface(包括注解类型)、枚举类
    FIELD, // 类的属性,包括枚举类型的属性
    METHOD, // 方法
    PARAMETER, // 方法参数
    CONSTRUCTOR, // 构造方法
    LOCAL_VARIABLE, // 局部变量
    ANNOTATION_TYPE, // 注释
    PACKAGE, // 包
    TYPE_PARAMETER, // 泛型,JDK1.8新增
    TYPE_USE // 任何使用到对象的地方,JDK1.8新增
}

5,注解的使用

  由以上分析可知,元注解中对注解开发来讲最重要的是@Target和@Retention。
@Target代表注解修饰的元素类型,@Retention表示注解的使用期。
@Retention中,RetentionPolicy.SOURCE 能够用来开发一些编译器的警告提示之类,通常不用。
RetentionPolicy.CLASS能够将信息写到class文件中但又在JVM中不使用,须要配合字节码工具使用,通常不用。
RetentionPolicy.RUNTIME是常常使用的,在运行期反射获得注解信息。

6,注解反射的API
  反射中常常使用的是Class、Constructor、Field、Method、Packge都是直接过间接实现了AnnotatedElement接口来读取注解信息。写反射的文章中也提到过。

AnnotatedElement的源码:

package java.lang.reflect;
public interface AnnotatedElement {
    // 该元素上是否有制定类型的注解
    default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
        return getAnnotation(annotationClass) != null;
    }

    // 获取元素上指定类型的注解
    <T extends Annotation> T getAnnotation(Class<T> annotationClass); 

    // 获取元素上的全部注解
    Annotation[] getAnnotations();

    // 获取元素本身的全部注解,不包括继承来的
    Annotation[] getDeclaredAnnotations(); 

    // 配合@Repeatable注解使用
    default <T extends Annotation> T[] getAnnotationsByType(Class<T> annotationClass) {
         T[] result = getDeclaredAnnotationsByType(annotationClass);
         if (result.length == 0 && this instanceof Class && AnnotationType.getInstance(annotationClass).isInherited()) { 
             Class<?> superClass = ((Class<?>) this).getSuperclass();
             if (superClass != null) {
                 result = superClass.getAnnotationsByType(annotationClass);
             }
         }
         return result;
     }

    // 获取元素的指定类型的注解,不包括继承来的
    default <T extends Annotation> T getDeclaredAnnotation(Class<T> annotationClass) { 
         Objects.requireNonNull(annotationClass);
         for (Annotation annotation : getDeclaredAnnotations()) {
             if (annotationClass.equals(annotation.annotationType())) {
                 // More robust to do a dynamic cast at runtime instead
                 // of compile-time only.
                 return annotationClass.cast(annotation);
             }
         }
         return null;
     }

    // 配合@Repeatable注解使用
    default <T extends Annotation> T[] getDeclaredAnnotationsByType(Class<T> annotationClass) { 
        Objects.requireNonNull(annotationClass);
        return AnnotationSupport.
            getDirectlyAndIndirectlyPresent(Arrays.stream(getDeclaredAnnotations()).
                collect(Collectors.toMap(Annotation::annotationType,
                    Function.identity(), ((first,second) -> first), LinkedHashMap::new)),  annotationClass);
    }
}

注意
  注解的继承@Inherited是针对类的,只对类的继承有效果,方法的重写是继承不了的。

参考资料:

  1. 以上内容为笔者平常琐屑积累,已无从考究引用。若是有,请站内信提示。
相关文章
相关标签/搜索