前言
java官方文档中有这么一句话:注解用于为Java代码提供元数据。作为元数据,注解并不会直接影响代码的执行,但也有一些类型的注解可以用于此目的。我们使用注解的过程中也常常能体会到这一点,比如@RequestMapping可以为我们提供请求地址的元数据,还可以为我们指定请求方式。
注解是一种标记式的高耦合的配置方式,不像XML那么松散,它直接配置在目标对象上,不论是类、方法或是字段。这样的方式更加的便捷,易于维护和修改,当然,付出的代价就是耦合度高了很多。
本文我们将从元注解,Java内置注解,自定义注解这三个方面层层递进地讲解。
一、元注解
元注解是用来修饰注解的注解,如我们常见的@Override,用来修饰它的注解就是元注解。元注解一般用来指定注解的作用范围,生命周期等信息。
元注解主要有@Target、@Retention、@Documented、@Inherited、@Repeatable(JDK1.8新引入)。
@Target
- 指定注解的作用范围,用枚举类作为表达类型,注解的作用范围可以是类,方法、变量等。
- @Target(ElementType.TYPE) 作用接口、类、枚举、注解
- @Target(ElementType.FIELD) 作用属性字段、枚举的常量
- @Target(ElementType.METHOD) 作用方法
- @Target(ElementType.PARAMETER) 作用方法参数
- @Target(ElementType.CONSTRUCTOR) 作用构造函数
- @Target(ElementType.LOCAL_VARIABLE)作用局部变量
- @Target(ElementType.ANNOTATION_TYPE)作用于注解(元注解本身的target就使用该属性)
- @Target(ElementType.PACKAGE) 作用于包
- @Target(ElementType.TYPE_PARAMETER) 作用于类型泛型,即泛型方法、泛型类、泛型接口 (jdk1.8新增)
- @Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型除了 class (jdk1.8新增)
@Retention
- 指定注解的生命周期。该注解的属性值有三个:
- @Retention(RetentionPolicy.SOURCE),注解仅存在于源码中,在class字节码文件中不包含
- @Retention(RetentionPolicy.CLASS), 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
- @Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在,在运行时可以通过反射获取到
- 这三种生命周期中,RUNTIME包含了CLASS和SOURCE,而CLASS又包含了SOURCE
@Documented
- 它的作用就是把注解写入到JavaDoc文档中
@Inherited
- 被@Inherited注解了的注解如果修饰了一个类,那么它的子类也默认会继承父类的注解
@Repeatable
- 意思是说被@Repeatable注解的注解可以同时作用于一个对象多次,每次作用时又能代表不同的含义
二、JDK内置注解
java为我们预定义了三种注解:@Override、@Deprecated、@SuppressWarnings
@Override的定义:
它的作用范围是方法,而且只在编译期间存在,编译结束时不会被写入class文件。因为它的作用只是在编译期间让编译器验证修饰的方法签名是否合法(即是否正确重写了父类方法),所以编译结束后就没有价值被保留下来了。
@ Deprecated的定义:
它能修饰绝大多数的类型,用来标记当前的类型已经不在推荐被使用了。之所以直接删除这些不推荐使用的对象是因为这些对象在别处往往被调用,随意删除会造成很大影响,一般都是在将来的某个版本中移除。
@SuppressWarnings
@SuppressWarnings主要用来抑制java的警告,它有一个value属性用来指定被抑制的警告的类型。例如:
我们定义了一个变量却未使用过,这时候就可以用@SuppressWarnings("unused")修饰a变量抑制警告了。
三、自定义注解的定义和使用
1、注解的定义
自定义注解用到的修饰符是@interface。注解只有成员变量,没有方法,注解的成员变量以“无参的方法”的形式声明。成员变量可以是基本数据类型,String类型、枚举类型、注解类型、Class类型以及这些类型的一维数组。注解一般都要赋初值,如果没有想要指定的值,字符类型一般赋值为"",int类型一般为-1。
这是一个用于分组的注解,规定分组人数最少为5人,最多为10人。
2、注解的使用与解析
我们把@GamingGroup()注解在divideIntoGroups()上,提供了元数据minNumber 5和maxNumber 10。
而在processAnnotationGroup()中对注解进行解析:
1、首先我们先获取divideIntoGroups()的Method对象;
2、然后再用Class类中的isAnnotationPresent()判断方法上有无注解我们需要解析的注解@GamingGroup,如果有则转入3;
/**
* {@inheritDoc}
* @throws NullPointerException {@inheritDoc}
* @since 1.5
* 判断有无注解对象
*/
@Override
public boolean isAnnotationPresent(Class<? extends Annotation> annotationClass) {
return GenericDeclaration.super.isAnnotationPresent(annotationClass);
}
3、我们通过getAnnotation方法得到@GamingGroup对象,并拿到maxNumber和minNumber值与传入的number比较,根据对应情况返回结果
/**
* @throws NullPointerException {@inheritDoc}
* @since 1.5
* 得到注解对象
*/
@SuppressWarnings("unchecked")
public <A extends Annotation> A getAnnotation(Class<A> annotationClass) {
Objects.requireNonNull(annotationClass);
return (A) annotationData().annotations.get(annotationClass);
}
结束语
到此对java注解的介绍就结束了,如果大家有不同的意见也可以在评论里面留言。