注解(也被称为元数据),为我们在代码中添加信息提供了一种形式化的方法,使我们可以在稍后某个时刻非常方便的使用这些数据。(通过反射的方式)
java中已经有的注解:
1 @override:表示当前的方法将覆盖超类中的方法(重写方法)
2 @Deprecated:表示已经废弃的方法,使用就会报错
3 @SuppressWarnings:关闭编译器警告信息

基本语法

注解的定义看起来像接口的定义,并且也会被编译称为class文件

  1. @Target(ElementType.METHOD)//表示可以标注的位置信息,此处为方法前
  2. @Retention(RetentionPolicy.RUNTIME)//表示运行时可以获取,通过反射可以获取
  3. public @interface Test {}
  1. public class Testable {
  2. public void execute(){
  3. System.out.println("Executing---");
  4. }
  5. @Test void test(){
  6. execute();
  7. }
  8. public static void main(String[] args) {
  9. final Testable testable = new Testable();
  10. testable.test();
  11. }
  12. }

@Target:用来定义注解放在什么地方(比如放在一个方法,或者是一个域)
@Retention:用来定义注解应用在哪一个级别(SOURCE表示在源代码中,CLASS表示在类文件中,RUNTIME,在运行时)

  1. @Target(ElementType.METHOD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface UseCase {
  4. public int id();
  5. public String description() default "no description";
  6. }

id和desctrition的定义类似于方法,但是description元素拥有一个default值,如果在注解某个方法时内有给出description的值,此时就会使用default值

  1. public class PasswordUtils {
  2. @UseCase(id = 47, description = "密码必须至少有一位")
  3. public boolean validatePassword(String password) {
  4. return (password.matches("\\w*\\d\\w*"));
  5. }
  6. @UseCase(id = 48)//在这里并没有给出description的值,所以处理时会使用该元素的默认值
  7. public String encryptPassword(String password) {
  8. return new StringBuilder(password).reverse().toString();//
  9. }
  10. @UseCase(id = 49, description = "不能够使用旧密码")
  11. public boolean checkForNewPassword(List<String> prePassword,String newPassword) {
  12. return !prePassword.contains(newPassword);
  13. }
  14. }

元注解

元注解专职负责其他的注解:
image.png
@Retention:SOURCE:被修饰的类,被编译后,丢弃该注解。CLASS:通过反射获取不到

编写注解处理器

在使用注解的过程中,很重要的一点就是使用注解处理器

  1. public class UseCaseTracker {
  2. public static void trackUseCases(List<Integer> useCases, Class<?> cl) {
  3. for (Method m : cl.getDeclaredMethods()) {//获取cl的所有的方法
  4. UseCase uc = m.getAnnotation(UseCase.class);//返回指定类型的注解对象
  5. if (uc != null){
  6. System.out.println("Fount Use Case: " + uc.id() + " " + uc.description());
  7. useCases.remove(new Integer(uc.id()));
  8. }
  9. }
  10. for (Integer i : useCases) {
  11. System.out.println("Not Fount Use Case " + i);
  12. }
  13. }
  14. public static void main(String[] args) {
  15. List<Integer> useCases = new ArrayList<>();
  16. Collections.addAll(useCases, 45, 46, 47, 48, 49, 50);
  17. System.out.println(useCases);
  18. trackUseCases(useCases, PasswordUtils.class);
  19. }
  20. }

注解元素

注解元素可用的类型:所有的基本类型,String,Class,enum,Annotation还有以上类型的数组。
但是不允许使用任何的包装器类型。注解也可以作为元素的类型,也就是说注解可以嵌套

默认值限制

元素不能有不确定的值,也就是说,元素必须要么具有默认值,要么在时用注解的时候提供元素的值

生成外部文件

如果希望提供一些基本的的对象/关系映射功能,能够自动生成数据库,用以存储对象,如果使用注解的话,就可以将所有的信息都保存在源文件中,为此我们需要一些新的注解,用来定义相关联的数据库表的名字,以及与属性相关联的列的名字和SQL类型。
注解的定义:

  1. @Target(ElementType.TYPE)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface DBTable {
  4. public String name() default "";
  5. }

在@Target注解中指定的每一个ElementType就是一个约束,它告诉编译器,这个自定义的注解只能应用于该类型

  1. @Target(ElementType.FIELD)
  2. @Retention(RetentionPolicy.RUNTIME)
  3. public @interface Constrains {
  4. boolean primaryKey() default false;
  5. boolean allowNull() default true;
  6. boolean unique() default false;
  7. }
  8. @Target(ElementType.FIELD)
  9. @Retention(RetentionPolicy.RUNTIME)
  10. public @interface SQLString {
  11. int value() default 0;
  12. String name() default "";
  13. Constrains constrains() default @Constrains;
  14. }
  15. @Target(ElementType.FIELD)
  16. @Retention(RetentionPolicy.RUNTIME)
  17. public @interface SQLInteger {
  18. String name() default "";
  19. Constrains constrains() default @Constrains;
  20. }

注解处理器通过@Constraints注解提取出数据库表的元数据,虽然对于数据库所能提供的所有约束而言,@Constraints注解值表示了它的一个很小的子集,primaryKey(),allowNull(),unique(),元素明智的提供了默认值
这些SQL类型具有name()元素和constraints()元素,后者利用了嵌套注解的功能,constraints()元素的默认值时@Constraints,由于在@Constraints注解类型之后,没有在括号中指明@Constraints中元素的值,因此constraints()元素的默认值实际上就是一个所有元素都为默认值的@Constraint注解

  1. @DBTable(name = "MEMBER")
  2. public class Member {
  3. @SQLString(30)
  4. String firstName;
  5. @SQLString(50)
  6. String lastName;
  7. @SQLInteger
  8. Integer age;
  9. @SQLString(value = 30, constrains = @Constrains(primaryKey = true)) String Handle;
  10. static int memberCount;
  11. public String getFirstName() {
  12. return firstName;
  13. }
  14. public String getLastName() {
  15. return lastName;
  16. }
  17. public Integer getAge() {
  18. return age;
  19. }
  20. public String getHandle() {
  21. return Handle;
  22. }
  23. }

这些注解第一:都使用了嵌入的@Constraint注解的默认值;第二:他们都是用了快捷方式(如果在注解中定义了名字为value的元素,并且在应用该注解的时候,如果该元素时唯一需要赋值的一个元素,那么此时无需使用名-值对的这种语法,只需要在括号内给出value元素所需要的值就可以了)

直接不支持继承

java中的注解时不可以使用extands关键字来继承某个@interface的;

实现注解处理器