JAVA注解基础知识

注解

注解是在 JDK5 时引入的新特性,JDK5 内部提供了三个注解

  • @Deprecated – 过时
  • @Override – 重写
  • @SuppressWarnings – 压制警告

1. 基本语法

1.1 注解声明

@Test 注解的声明:

@Retention(RetentionPolicy.RUNTIME)
@Target({ElementType.METHOD})
public @interface Test {
}
  • 使用了 @interface 声明了 Test 注解
  • 使用 @Target 注解传入 ElementType.METHOD 参数来标明该注解只能用于方法上。
  • 使用 @Retention(RetentionPolicy.RUNTIME) 用来表示该注解生存期是运行时。

从代码上看注解的定义很像接口的定义,确实如此,@Test 注解编译后也会生成 Test.class 文件。

1.2 元注解(标记其他注解的注解)

@Target 和 @Retention 是由 Java 提供的元注解,所谓元注解就是标记其他注解的注解。

  • @Target 用来约束注解可以应用的地方(如方法、类或字段),其中 ElementType 是枚举类型,其定义如下,也代表可能的取值范围:

    public enum ElementType {
        TYPE,				// 标明该注解可以用于类、接口(包括注解类型)或enum声明
        FIELD,				// 标明该注解可以用于字段(域)声明,包括enum实例
        METHOD,				// 标明该注解可以用于方法声明
        PARAMETER,			// 标明该注解可以用于参数声明
        CONSTRUCTOR,		// 标明注解可以用于构造函数声明
        LOCAL_VARIABLE,		// 标明注解可以用于局部变量声明
        ANNOTATION_TYPE,	// 标明注解可以用于注解声明(应用于另一个注解上)
        PACKAGE,			// 标明注解可以用于包声明
        TYPE_PARAMETER,		// 标明注解可以用于类型参数声明(1.8新增)
        TYPE_USE			// 类型使用声明
    }
    

    当注解未指定 Target 值时,则此注解可以用于任何元素之上,多个值使用{}包含并用逗号隔开:

    @Target(value={CONSTRUCTOR, FIELD, METHOD, PARAMETER, TYPE})
    
  • @Retention用来约束注解的生命周期,其中 RetentionPolicy 是枚举类型,定义如下:

    public enum RetentionPolicy {
        SOURCE,	// 该类型的注解信息只会保留在源码里,源码经过编译后,注解信息会被丢弃
        CLASS,	// 该类型的注解信息会保留在源码里和class文件里,在执行的时候,不会加载到虚拟机中(当注解未定义Retention值时,默认值是CLASS,如Java内置注解,@Override、@Deprecated、@SuppressWarnning等)
        RUNTIME	// 注解信息将在运行期(JVM)也保留,因此可以通过反射机制读取注解的信息(源码、class文件和执行的时候都有注解的信息),如SpringMvc中的@Controller、@Autowired、@RequestMapping等
    }	
    

JDK还提供了两个元注解:@Documented 和 @Inherited:

  • @Documented 被修饰的注解会生成到 javadoc中。
  • @Inherited 可以让注解被 ”继承“ ,但这并不是真的继承,只是通过使用 @Inherited,可以让子类对象使用getAnnotations() 方法获取到父类被 @Inherited 修饰的注解。

1.3 注解元素及其数据类型

​ 内部没有定义其他元素的注解称为标记注解(marker annotation),例如 @Test 注解。一般定义注解时都会包含一些元素以表示某些值,方便处理器使用,例如 @Component 注解:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Documented
@Indexed
public @interface Component {
	String value() default "";
}

​ 与前面 @Test 注解不同的是,它声明一个 String 类型的 value 元素,其默认值为空字符。注意:注解中任何元素的声明应采用方法的声明方式,同时可选择使用 default 提供默认值。注解支持的元素数据类型如下:

  • 所有基本类型(int,float,boolean,byte,double,char,long,short)
  • String
  • Class
  • enum
  • Annotation
  • 上述类型的数组

​ 声明注解元素时可以使用基本类型但不允许使用任何包装类型,同时还应该注意到注解也可以作为元素的类型(元素必须要么具有默认值,要么在使用注解时提供元素的值),也就是嵌套注解。使用示例:

@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface Reference {
    boolean next() default false;
}

enum Status {
    FIXED,
    NORMAL
}

@interface AnnotationElementDemo {

    // 枚举类型
    Status status() default Status.FIXED;

    // 布尔类型
    boolean showSupport() default false;

    // String类型
    String name() default "";

    // class类型
    Class<?> testCase() default Void.class;

    // 注解嵌套
    Reference reference() default @Reference(next=true);

    // 数组类型
    long[] value();
}

备注:

  • 注解是不支持继承的,因此不能使用关键字 extends 来继承某个 @interface。
  • 如果注解中定义了名为 value 的元素,在使用该注解时,如果该元素是唯一要赋值的一个元素,那么无需使用key = value 的语法,只需在括号内给出 value 元素所需的值即可,但是元素名必须为 value。例如 @Component 注解。

2. 注解与反射机制

​ Java 中所有注解都隐式继承了 Annotation 接口。java.lang.reflect 包下的 AnnotatedElement 接口则用于表示目前正在 VM 中运行的程序中已使用注解的元素,通过该接口提供的方法可以利用反射读取注解信息,反射包的 Constructor 类、Field 类、Method 类、Package 和 Class 类等都实现了 AnnotatedElement 接口(注解都可以在这些元素上进行标注)。

​ AnnotatedElement 中相关的方法如下:

/** 该元素如果存在指定类型的注解,则返回这些注解,否则返回 null */
<T extends Annotation> T getAnnotation(Class<T> annotationClass);	

/** 返回此元素上存在的所有注解,包括从父类继承的 */
Annotation[] getAnnotations();

/** 如果指定类型的注解存在于此元素上,则返回 true,否则返回 false */
default boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
	return getAnnotation(annotationClass) != null;
}

/** 返回直接存在于此元素上的所有注解,注意,不包括父类的注解, */
Annotation[] getDeclaredAnnotations();

3. JDK8 注解增强

​ 元注解 @Repeatable 是 JDK8 新加入的,它表示在同一个位置可以重复相同的注解:

@FilterPath("/web/update")
@FilterPath("/web/add")
public class A {
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
public @interface FilterPaths {	
    FilterPath[] value();
}
@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Repeatable(FilterPaths.class)
public @interface FilterPath {
    String value();
}

​ 可以简单理解为通过使用 @Repeatable 后,将使用 @FilterPaths 注解作为接收同一个类型上重复注解的容器,而每个 @FilterPath 则负责保存指定的路径串。

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值