Java注解
对应《疯狂Java讲义(第5版)》14 章节
Annotation 注解概述
写在接口、类、属性、方法上的一个标签,或者说是一个特殊形式的注释
可以在编译、类加载、运行时被读取,注解在代码运行时是可以被反射读取并进行相应的操作,而如果没有使用反射或者其他检查,那么注解是没有任何真实作用的,也不会影响到程序的正常运行结果
提供为程序元素(接口、类、属性、方法)设置元数据(描述数据的数据)的方法,存储在 “name = value” 对中
通常来说注解分为以下三类
- 基本注解 – Java提供的基础注解,标明过期的元素/标明是复写父类方法的方法/标明抑制警告。
- 元注解 – java内置的注解,标明该注解的使用范围、生命周期等。
- 自定义注解 – 第三方定义的注解,含义和功能由第三方来定义和实现。
基本注解
位于 java.lang.*
@Override 标记一个方法是覆写父类方法
可以避免方法签名错误
@Deprecated 标记一个元素为已过期,避免使用
- since: 指定从哪个版本被标记为过时
- forRemoval: 将来是否会被删除
支持的元素类型为:CONSTRUCTOR, FIELD, LOCAL_VARIABLE, METHOD, PACKAGE, PARAMETER, TYPE
@SuppressWarnings 不输出对应的编译警告
可以抑制该元素及其所有子元素的编译器警告
1
@SuppressWarnings(value = "unchecked")
@SafeVarargs 抑制堆污染
Heap pollution(堆污染), 指的是当把一个不带泛型的对象赋值给一个带泛型的变量时, 就有可能发生堆污染。堆污染在编译时并不会报错, 只会在编译时提示有可能导致堆污染的警告. 在运行时,如果发生了堆污染, 那么就会抛出类型转换异常。
1
2
3
4
5
6
7// list 定义时未指定泛型,实际上集合中存储为Integer类型
List list = new ArrayList<Integer>();
list.add(1);
// 将无泛型的list对象,赋值给指定类型的strList变量, 此处已经发生堆污染
List<String> strList = list;
// 抛出异常 java.lang.ClassCastException
String str = strList.get(0);@FunctionalInterface 表明这是一个函数式接口
函数式接口:只含一个抽象方法的接口
元注解
位于 java.lang.annotation.*, 标注在自定义注解处
@Retention 标明自定义注解的生命周期
从编写Java代码到运行主要周期为
源文件
→Class文件
→运行时数据
,@Retention则标注了自定义注解的信息要保留到哪个阶段,分别对应的value取值为SOURCE
→CLASS
→RUNTIME
。默认值为class1
2
3
4
5
6@Documented
@Retention(RetentionPolicy.RUNTIME)
@Target(ElementType.ANNOTATION_TYPE)
public @interface Retention {
RetentionPolicy value();
}@Target 描述自定义注解的使用范围
值 说明 TYPE 类、接口、注解、枚举 FIELD 成员变量 METHOD 方法 PARAMETER 方法参数 CONSTRUCTOR 构造函数 LOCAL_VARIABLE 局部变量(如循环变量、catch参数) ANNOTATION_TYPE 注解 PACKAGE 包 TYPE_PARAMETER 泛型参数 jdk1.8 Java8 TYPE_USE 任何元素 jdk1.8 Java8 @Inherited 是否可以被标注类的子类继承
1
2
3
4
5
6@Target(ElementType.TYPE)
@Retention(RetentionPolicy.RUNTIME)
@Inherited
public @interface Inheritable
{
}在自定义的注解标注到某个类时,该类的子类会继承这个自定义注解。这里需要注意的是只有当子类继承父类的时候,注解才会被继承,类实现接口,或者接口继承接口,都是无法获得父接口上的注解声明的
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16// 使用@Inheritable修饰的Base类
@Inheritable
class Base
{
}
// TestInheritable类只是继承了Base类,
// 并未直接使用@Inheritable Annotiation修饰
public class InheritableTest extends Base
{
public static void main(String[] args)
{
// 打印TestInheritable类是否具有@Inheritable修饰
System.out.println(InheritableTest.class
.isAnnotationPresent(Inheritable.class));
}
}@Repeatable 是否可以重复标注
@Documented 是否在生成的JavaDoc文档中体现
被标注该注解后,生成的javadoc中,会包含该注解
自定义注解 (@interface)
1 |
|
1 |
|
提取注解信息
1
2
3
4
5
6
7
8
9
10
11@MethodAnnotation(name="cngo", age=6)
public void test() throws NoSuchMethodException, SecurityException, ClassNotFoundException{
Annotation[] aArray = Class.forName("Test").getMethod("test").getAnnotations();
for(var an: aArray){
if(an instanceof MethodAnnotation){
System.out.println(((MethodAnnotation) an).name());
System.out.println(((MethodAnnotation) an).age());
}
System.out.println(an);
}
}重复注解
注解容器 与 @Repeatable
类型注解
编译时处理注解
APT(Annotation Processing Tool),注解处理工具,找出原文件注解信息并进行处理,生成额外的源文件或其他文件
1
2//指定注解处理器
javac -processor HibernateAnnotationProcessor Person.java
注解处理器需要实现 javax.annotation.processing 包下的 Process 接口,可继承 AbstractProcessor 方式实现注解处理器