注解
提出问题
概述
是什么
注解(元数据)为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便地使用这些数据。
分类,各个分类是什么
- 标记注解,没有元素的注解
优缺
- 注解可以提供用来完整地描述程序所需的信息,而这些信息是无法用Java表达的
- 注解使得我们能够以将由编译器来测试和验证的格式,存储有关程序的额外信息,注解可以用来生成描述符文件,甚至是新的类定义,并且有助于减轻编写“样板”代码的负担。
- 可以将元数据保存在Java源代码中,并利用annotationAPI为自己的注解构造处理工具
- 更加干净易读的代码以及编译期类型检查
为什么要用(作用)
- 每当你创建描述符性质的类或接口时,一旦其中包含了重复性的工作,那就可以考虑使用注解来简化与自动化该过程
应用场景
常见注解
Java内置
- @Override。表示当前方法定义将覆盖超类中的错误,如果没有覆盖,则编译器发出错误提示
- @Deprecated。如果程序使用了注解为它的元素,编译器会发出警告
- @SuppressWarnings,关闭不当的编译器警告信息。
基本语法
定义注解
1 | (ElementType.METHOD) |
注解的定义类似于定义一个接口,除了多出一个@,在定义注解时会需要一些元注解。
成员
在注解中会包含一些元素来表示某些值,当分析处理注解时,程序可以利用这些值,注解的元素类似接口的方法,唯一的区别是你可以为其指定默认值。
示例
1 | (ElementType.METHOD) |
该注解用于跟踪一个项目中的用例,如果一个方法实现了某个用例的需求则可以加上该注解
1 | 47) (id = |
注解的元素在使用时表现为键值对的形式,置于@UseCase声明后的括号内。
元注解
- @Target:定义你的注解将运用到什么地方,例如一个方法或者域
- Retention:定义该注解在哪个级别可用,Source(源代码)、CLASS(类文件)、RUNTIME(运行时)
- @Documented,将此注解包含在JavaDoc中
- @Inherited,允许子类继承父类中的注解。
注解元素
注解@UseCase由UseCase.jva定义,其中可以包含的可用类型有:
- 所有基本类型int 、float、boolean
- String
- Class、enum
- Annotation
- 数组
默认值限制
- 编译器要求元素不能有不确定的值,即元素要么具有默认值,要么在使用注解时提供元素的值
- 对于非基本类型的元素,无论是源代码声明或者定义默认值均不能为null。即所有元素都存在,因此只能以空字符串、负数来表示元素不存在
嵌套注解
将Constraints
注解嵌入到SQLString
当中,并且值是默认的
1 | public SQLString { |
若想要改变内部的值,则需要
1 | public SQLString { |
快捷方式
当注解中定义了名为value的元素,并且在赋值时是唯一需要赋值的一个元素,此时无需使用键值对的语法,只需要赋值即可,这可以用于任何类型的元素。
编写注解处理器
Java通过反射机制构造注解处理器。并且Java提供了外部工具apt解析带有注解的Java代码
1 | public class UseCaseTracker { |
生成外部文件
有些framework需要一些额外的信息才能与你的源代码协同工作,而这种情况最适合注解实现价值。
如果你希望提供一些基本的对象/关系映射功能,能够自动生成数据库表用于存储JavaBean对象
- 可以选择XML描述文件,指明类的名字、每个成员以及数据库映射的相关信息。
- 使用注解将所有信息保存在Java源文件中。
首先定义@DBTable
1 | // Applies to classes only (ElementType.TYPE) |
为修饰JavaBean准备的注解
注解处理器通过@Constraints
提取出数据库表的元数据,尽管该注解只提供了数据库约束的一个很小的子集,但依然是一种帮助
1 | (ElementType.FIELD) |
内部使用了嵌套注解@Constraints
将CoLumn的约束嵌入,
1 | (ElementType.FIELD) |
1 | (ElementType.FIELD) |
示例
1 | "MEMBER") (name = |
Bean对应的表名为MEMBER,其内部有firstName等元素,值为30、50.
注解处理器
1 | public class TableCreator { |
Main方法会处理命令行传入的每个类名,用forName加载每个类,并检查类是否带有@DBTable注解,如果有就将发现的表名保存,并读取所有域。等等