1. 注解(Annatation)概述
注解(Annotation)是 JDK1.5 之后的新特性,是 Java 提供用于设置程序中元素的关联信息和元数据(MetaData)的方法。它本质是一个接口,程序可以通过反射来获取指定程序中元素的 Annotation 注解对象,然后通过该 Annotation 对象来获取注解中的元数据信息。
注解可以标记在类、接口、方法、成员变量,构造方法,局部变量等等元素上。
Tips: 可以理解为,注解是给编译器或 JVM 查看的,然后可以根据其标记执行对应的功能。
2. 注解作用
2.1. 注解使用例子
- 编译检查,如
@Override。 - 生成帮忙文档
- 做为框架的配置方案(重点)
- XML配置
- 注解配置
2.2. 扩展:框架的两种配置方案优缺点
注:框架 = 代码 + 配置(个性化)。框架(struts2,hibernate,spring)都提供了两种配置方案
- XML 配置:
- 优点:配置信息和类分离,降低程序的耦合性(扩展性更好)
- 缺点:每一个类需要对应一个XML文件,如果类很多,而XML文件也会很多。XML 维护成本高(可读性差)
- 注解配置:
- 优点:将配置信息和类写在一起,可读性高,开发效率相对较高。
- 缺点:程序耦合性高
3. Java常用内置注解的使用
3.1. @Override 注解
该注解只能用于修饰方法声明,表示该方法是限定重写父类方法。该注解只能用于方法
3.2. @Deprecated 注解
用于表示某个程序中的元素(类,方法等)已经过时。不建议继续使用,还是可以使用。
3.3. @SuppressWarnings 注解
@SuppressWarnings 注解的作用是抑制编译器警告。常用警告名称:
- deprecation 忽略过时
- rawtypes 忽略类型安全
- unused 忽略不使用
- unchecked 忽略安全检查
- null 忽略空指针
- all 忽略所有编译器警告
注:如果多个警告就使用{}将多个警告包括起来,封装成字符串数组
4. 自定义注解
属性的作用:可以给每个注解加上多个不同的属性,用户使用注解的时候,可以传递参数给属性,让注解的功能更加强大
4.1. 自定义注解格式
| |
4.2. 注解的属性
4.2.1. 属性定义格式
- 第1种定义方式:
数据类型 属性名(); - 第2种定义方式:
数据类型 属性名() default 默认值; - 注意事项:
- 如果注解有定义了属性,且属性没有默认值,则在使用注解的时候,就需要给属性赋值
- 如果属性有默认值,则使用注解的时候,这个属性就可以不赋值。也可以重新赋值,覆盖原有的默认值
4.2.2. 注解支持的数据类型
- 8种数据类型都支持
- String
- Enum
- Class
- Annotation
- 以及上面类型的数组形式
4.3. 特殊属性名 value
- 如果注解中只有一个属性且属性名为
value时,在使用注解时可以直接给出属性值而不需要给属性名。(省略value=部分) - 无论这个 value 是单个元素还是数组,都可以省略。
- 如果注解中除了 value 属性还有其他属性,且其他属性中至少有一个属性没有默认值时,则 value 属性名不能省略。
| |

5. 元注解
5.1. 元注解的概念
Java 默认提供的注解,用于标识在注解上的注解,用来约束注解的功能,称为元注解。Java 所有的内置注解定义都使用了元注解。元注解有以下几个:
@Target:修饰的对象范围@Retention:定义被保留的时间长短@Inherited:阐述了某个被标注的类型是被继承的@Documented:描述-javadoc
5.2. @Target 元注解
@Target:标识注解使用范围(写在自定义注解类上)。Annotation可被用于 packages、types(类、接口、枚举、Annotation 类型)、类型成员(方法、构造方法、成员变量、枚举值)、方法参数和本地变量(如循环变量、catch 参数),如果不写默认是任何地方都可以使用。使用格式如下:
| |
@Target 可选取值来自 ElementType 枚举类:
ElementType.TYPE: 用在类、接口(包括注解类型)或者枚举(enum)上ElementType.FIELD:用在成员变量上ElementType.METHOD: 用在成员方法上ElementType.PARAMETER:用在方法参数(形式参数)上ElementType.CONSTRUCTOR:用在构造方法上ElementType.LOCAL_VARIABLE:用在局部变量上ElementType.ANNOTATION_TYPE:用过声明一个注解ElementType.PACKAGE:用于描述包ElementType.TYPE_PARAMETER:JDK1.8 以后加入,对普通变量的声明ElementType.TYPE_USE:JDK1.8 以后加入,能标注任何类型的名称
5.3. @Retention 元注解
@Retention:用来标识注解的生命周期(有效作用范围),表示需要在什么级别保存注解信息。使用格式如下:
| |
@Retention 可选取值来自 RetentionPolicy 枚举类:
RetentionPolicy.SOURCE:注解只存在于 Java 源代码中,编译生成字节码文件和程序运行时就不存在了。(即源文件保留)RetentionPolicy.CLASS:默认值,注解存在于 Java 源代码、编译以后的字节码文件中,运行的时候内存就不存在。(即 class 保留)RetentionPolicy.RUNTIME:注解存在于 Java 源代码中、编译以后的字节码文件中、运行时的内存中,程序可以通过反射获取该注解。(即运行时保留)
5.4. @Inherited 元注解
@Inherited 作用:表示该注解可以被子类继承。如果一个使用了 @Inherited 修饰的 annotation 类型被用于一个 class,则这个 annotation 将被用于该 class 的子类。使用格式如下:
| |
5.5. @Documented 元注解
@Documented 作用:表示该注解会出现在帮忙文档(javadoc)中。描述其它类型的 annotation 应该被作为被标注的程序成员的公共 API,因此可以被例如 javadoc 此类的工具文档化。使用格式如下:
| |
6. 注解的原理
6.1. Annotation 接口
所有注解类型的公共接口,所有注解都是 java.lang.annotation.Annotation 的子类(类似所有类都 Object 的子类)
6.2. AnnotatedElement 接口
该接口中定义了一系列与注解解析相关的方法。注:当前对象是指方法调用者
| |
- 判断当前对象是否使用了指定annotationClass的注解。如果使用了,则返回true,否则返回false
| |
- 根据注解的Class类型获得当前对象上指定的注解对象(注解类的对象)。需要向下转型成注解的类型,然后才能调用注解里的属性。
| |
- 获得当前对象及其从父类上继承的所有的注解对象数组
| |
- 获得类中所有声明的注解,不包括父类的
6.3. 注解原理简述
注解本质是一个继承了 Annotation 的特殊接口,其具体实现类是 Java 运行时生成的动态代理类。通过反射获取注解时,返回的是 Java 运行时生成的动态代理对象。通过代理对象调用自定义注解的方法,最终会调用 AnnotationInvocationHandler 的 invoke 方法。该方法会从 memberValues 这个 Map 中索引出对应的值。而 memberValues 的来源是 Java 常量池。
7. 注解解析
7.1. 解析原则
注解作用在哪个成员上,就通过该成员对应的对象获得注解对象。
比如,注解作用在成员方法上,则通过成员方法对应的Method对象获得;作用在类上的,则通过Class对象获得
| |
7.2. 注解解析案例
| |

