了解Java注解|Java基础

274 阅读3分钟

这是我参与8月更文挑战的第2天,活动详情查看:8月更文挑战

注解

注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。(摘自百度百科)

如何声明一个注解

定义一个注解与类不同,用@interface修饰,并且修饰在"注解"之上的注解称之为元注解。

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

@Target(ElementType.TYPE_PARAMETER)
@Retention(RetentionPolicy.CLASS)
public @interface CustonAnnotation {
    String name() default "Shixf";
}

定义完成后光标放到注解名上Ctrl+U。(IDEA打开父类的接口方法快捷键)所有注解默认Annotation接口。


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

元注解

  • 元注解: 在定义注解时,也可以使用其他的注解声明。对注解类型进行注解的注解称之为 meta-anntotain(元注解)。
  • @Target: 限制可以应用注解的 Java 元素类型。目标注解指定以下元素类型之一作为其值。
public enum ElementType {
    /** 类、接口(包括注解类型)或枚举声明 */
    TYPE,

    /**应用于成员变量(包括枚举常量) */
    FIELD,

    /** 限定应用于方法上*/
    METHOD,

    /**方法的参数的 */
    PARAMETER,

    /**应用于构造函数 */
    CONSTRUCTOR,

    /** 应用与方法内的局部变量 */
    LOCAL_VARIABLE,

    /** 应用于注解类型 */
    ANNOTATION_TYPE,

    /** 应用于包上 */
    PACKAGE,

    /**
     * Type parameter declaration
     * 形参,泛型上
     * @since 1.8
     */
    TYPE_PARAMETER,

    /**
     * Use of a type
     * 可以应用于任意使用类型的地方
     * @since 1.8
     */
    TYPE_USE
}

对TYPE_PARAMETER特别说明下,Jdk1.8引入的可以作用于泛型上,我还没有见到在哪里有用过,对这块有研究的大佬可以@我下。 image.png 注:这个注解在上文声明过。


  • @Retention:注解的保留级别
public enum RetentionPolicy {
    /**
     * 标记的注解仅保留在源码级别,被编译器忽略
     */
    SOURCE,

    /**
     * 标记的注解在编译时有编译器保留,但是Java虚拟机会忽略它
     */
    CLASS,

    /**
     * 标记的注解由JVM保留,因此运行时环境可以使用它
     */
    RUNTIME
}

另外还有 @Documented 与  @Inherited 元注解,前者用于被javadoc工具提取成文档,后者表示允许子类 继承父类中定义的注解。这里不做过多解释。不解释不代表不重要。

注解的应用场景

按照 @Retention 元注解定义的注解存储方式,注解可以被在三种场景下使用

  • SOURCE:作用于源码级别,可提供给IDE语法检查、APT等场景使用(在类中使用 SOURCE 级别的注解,编译之后的class中不存在) 例如Android中的@Dimension
@Documented
@Retention(SOURCE)
@Target({METHOD,PARAMETER,FIELD,LOCAL_VARIABLE,ANNOTATION_TYPE})
public @interface Dimension {
    @Unit
    int unit() default PX;

    int DP = 0;
    int PX = 1;
    int SP = 2;

    @IntDef({PX, DP, SP})
    @Retention(SOURCE)
    @interface Unit {}
}

原本我认为findViewById中@IdRes是用SOURCE级别,原来人家使用的是CLASS级别,拿个小本本记上,研究下。 image.png

  • CLASS:定义为CLASS的注解,会保留在class文件中,但是会被虚拟机忽略(即无法在运行时反射获取注解)。此时完全符合此种注解的应用场景为字节码操作,如AspectJ、热修复Roubust中。
  • RUNTIME:注解保留至运行期,意味着我们能够在运行期结合反射技术获取注解中的所有信息。