注解分类
- 自带注解@Override@Deprecated等
- 元注解 @Retention @Target @Inherited @Documented @Repeatable 修饰注解的注解
- 自定义注解
常用注解说明
常用的Java注解如下:
1、@Deprecated – 所标注内容不再被建议使用;
2、@Override – 只能标注方法,表示该方法覆盖父类中的方法;
3、@Documented --所标注内容可以出现在javadoc中;
4、@Inherited – 只能被用来标注“Annotation类型”,它所标注的Annotation具有继承性;
5、@Retention – 只能被用来标注“Annotation类型”,而且它被用来指定Annotation的RetentionPolicy属性;
6、@Target – 只能被用来标注“Annotation类型”,而且它被用来指定Annotation的ElementType属性;
7、@SuppressWarnings – 所标注内容产生的警告,编译器会对这些警告保持静默;
8、@interface – 用于定义一个注解;
其中,4、5、6、8多用于自定义注解,读者着重记一下。
自定义注解
我们使用@interface 来申明注解,如下:
// 定义一个空注解
public @interface MyAnnotation{}
配合一些元注解,根据自己需求,可以实现自定义注解了。
常用的元注解有@Retention、 @Target、 @Document、 @Inherited和@Repeatable五个。
五个元注解的说明
@Retention
1.Retention英文意思有保留、保持的意思,它表示注解存在阶段是保留在源码(编译期),字节码(类加载)或者运行期(JVM中运行)。
在@Retention注解中使用枚举RetentionPolicy来表示注解保留时期:
- @Retention(RetentionPolicy.SOURCE),注解仅存在于源码中,在class字节码文件中不包含
- @Retention(RetentionPolicy.CLASS), 默认的保留策略,注解会在class字节码文件中存在,但运行时无法获得
- @Retention(RetentionPolicy.RUNTIME), 注解会在class字节码文件中存在,在运行时可以通过反射获取到
2.如果我们是自定义注解,则通过前面分析,我们自定义注解如果只存着源码中或者字节码文件中就无法发挥作用,而在运行期间能获取到注解才能实现我们目的,所以自定义注解中肯定是使用 @Retention(RetentionPolicy.RUNTIME),如下:
@Retention(RetentionPolicy.RUNTIME)
public @interface MyTestAnnotation {
}
@Target
Target的英文意思是目标,这也很容易理解,使用@Target元注解表示我们的注解作用的范围就比较具体了,可以是类,方法,方法参数变量等,同样也是通过枚举类ElementType表达作用类型:
@Target(ElementType.TYPE) 作用接口、类、枚举、注解
@Target(ElementType.FIELD) 作用属性字段、枚举的常量
@Target(ElementType.METHOD) 作用方法
@Target(ElementType.PARAMETER) 作用方法参数
@Target(ElementType.CONSTRUCTOR) 作用构造函数
@Target(ElementType.LOCAL_VARIABLE)作用局部变量
@Target(ElementType.ANNOTATION_TYPE)作用于注解(@Retention注解中就使用该属性)
@Target(ElementType.PACKAGE) 作用于包
@Target(ElementType.TYPE_PARAMETER) 作用于类型泛型,即泛型方法、泛型类、泛型接口 (jdk1.8加入)
@Target(ElementType.TYPE_USE) 类型使用.可以用于标注任意类型除了 class (jdk1.8加入)
一般比较常用的是ElementType.TYPE类型,如下:
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.TYPE)
public @interface MyTestAnnotation {
}
@Documented
Document的英文意思是文档。它的作用是能够将注解中的元素包含到 Javadoc 中去。
@Inherited
Inherited的英文意思是继承,但是这个继承和我们平时理解的继承大同小异,一个被@Inherited注解了的注解修饰了一个父类,如果他的子类没有被其他注解修饰,则它的子类也继承了父类的注解。
@Repeatable
Repeatable的英文意思是可重复的。顾名思义说明被这个元注解修饰的注解可以同时作用一个对象多次,但是每次作用注解又可以代表不同的含义。
注解的源码分析
我们以@Override注解为例,来分析其源码,想查看一个普通类一样,按住ctrl键点击@Override即可进入其源码,如下:
@Target(ElementType.METHOD)
@Retention(RetentionPolicy.SOURCE)
public @interface Override {
}
我们看到@Override注解就是通过@interface注解定义的一个普通注解,而我们知道,使用 @interface 定义注解时,意味着它实现了 java.lang.annotation.Annotation 接口,即该注解就是一个Annotation
注意:定义 Annotation 时,@interface 是必须的,它和我们通常的 implemented 实现接口的方法不同。Annotation 接口的实现细节都由编译器完成。通过 @interface 定义注解后,该注解不能继承其他的注解或接口。
下面我们来分析一下Annotation 类的源码,如下:
public interface Annotation {
boolean equals(Object var1);
int hashCode();
String toString();
Class<? extends Annotation> annotationType();
}
通过以上源码,我们知道注解本身就是Annotation接口的子接口,也就是说注解中其实是可以有属性和方法,但是接口中的属性都是static final的,对于注解来说没什么意义,而我们定义接口的方法就相当于注解的属性,也就对应了前面说的为什么注解只有属性成员变量,其实他就是接口的方法,这就是为什么成员变量会有括号,不同于接口我们可以在注解的括号中给成员变量赋值。
Java注解的架构
根据上述的源码分析,我们得出Java注解(Annotation)的架构如下:
注解是接口类,都继承自Annotation接口类
1 个 Annotation 和 1 个 RetentionPolicy 关联
可以理解为:每1个Annotation对象,都会有唯一的RetentionPolicy属性;
1 个 Annotation 和 1~n 个 ElementType 关联
可以理解为:对于每 1 个 Annotation 对象,可以有若干个 ElementType 属性;
Annotation 有许多实现类,包括:Deprecated, Documented, Inherited, Override 等等。
Annotation 的每一个实现类都和1个 RetentionPolicy 关联并且和 1~n 个 ElementType 关联。
#注解的作用
在说注解的用途之前,我们先介绍下XML和注解区别:
- 注解:是一种分散式的元数据,与源代码紧绑定。
- xml:是一种集中式的元数据,与源代码无绑定
- 这部分多用于Java后台的配置项开发中,我们知道几年前服务器的配置项多存放在一个xml文件- 中,而spring 2.5 之后开始基于注解配置,从而实现了代替配置文件的功能。
注解的用途有很多,上面的只是一个简单的例子,总起起来,注解有如下四大部分作用:
- 1、生成文档,通过代码里标识的元数据生成javadoc文档。
- 2、编译检查,通过代码里标识的元数据让编译器在编译期间进行检查验证。
- 3、编译时动态处理,编译时通过代码里标识的元数据动态处理,例如动态生成代码。
- 4、运行时动态处理,运行时通过代码里标识的元数据动态处理,例如使用反射注入实例