JAVA自定义注解示例详解

    xiaoxiao2025-03-23  19

    什么是JAVA注解?这是百度百科的解释:

           定义:注解(Annotation),也叫元数据。一种代码级别的说明。它是JDK1.5及以后版本引入的一个特性,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。

           作用分类:

          ①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】

          ②代码分析:通过代码里标识的元数据对代码进行分析【使用反射】

          ③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】         

          写过JAVA代码的人对注解都不陌生,尤其在各种框架中很常见。这些注解都非常优秀,也很容易理解,但是,为什么要使用注解?注解是如何工作的?让我自定义一个注解来解释,相信理解了这个示例以后。

          首先我们分析一个很简单的场景,我们有一个叫Person的POJO类,代码如下:      

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 public class Person {      private String name;      private String age;        public String getName() {          return name;      }      public void setName(String name) {          this .name = name;      }      public String getAge() {          return age;      }      public void setAge(String age) {          this .age = age;      }      @Override      public String toString() {          return "Person [name=" + name + ", age=" + age + "]" ;      } }

            然后有这样一个HashMap:

    1 2 3 4 5 private static Map input = new HashMap(); static {          input.put( "name" , "Boaz" );          input.put( "age" , "29" ); }           需求是把这个HashMap的值转换为Person这个pojo类,map中的key值和Person类中的属性名是相同的,我们使用反射的方式来实现,完整代码如下:

    1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 public class Main {      private static Map input = new HashMap();      static {          input.put( "name" , "Boaz" );          input.put( "age" , "29" );      }      public static void main(String[] args) {          Person person = Map2Pojo(input, Person. class );          System.out.print(person);      }      private static <T> T Map2Pojo(Map input, Class<T> clazz) {          Method[] methods = clazz.getMethods();          T t;          try {              t = clazz.newInstance();          } catch (Exception e) {              e.printStackTrace();              return null ;          }          for (Method method : methods) {              input.keySet().forEach((key) -> {                  if (( "set" + key).equals(method.getName().toLowerCase())) {                      try {                          method.invoke(t, input.get(key));                      } catch (Exception e) {                          e.printStackTrace();                          return ;                      }                  }              });          }          return t;      } } 现在这个 Map2Pojo工具类已经可以工作了,但是现在来了一个新Map 1 2 3 4 5 6 private static Map input = new HashMap();   static {      input.put( "Name" , "Boaz" );      input.put( "Age" , "29" ); } 跟之前的Map没有什么不同,只是key值的首字母大写了,显然,上面的 Map2Pojo工具类这个时候就不能工作了。Map2Pojo是一个通用类,可以为 很多Pojo转换服务,显然在这个类里为这个情况添加if-else是不合适的 这个时候就是注解登场了,我们在Person类中增加如下自定义注解: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 public class Person {      private String name;      private String age;      public String getName() {          return name;      }      @MapKey (KeyName = "Name" )      public void setName(String name) {          this .name = name;      }      public String getAge() {          return age;      }      @MapKey (KeyName = "Age" )      public void setAge(String age) {          this .age = age;      }      @Override      public String toString() {          return "Person [name=" + name + ", age=" + age + "]" ;      } } 跟上面恩Person类相比,在Set方法上增加了注解 @MapKey,这是一个自定义注解,该注解源码如下: 1 2 3 4 5 @Target (ElementType.METHOD) @Retention (RetentionPolicy.RUNTIME) public @interface MapKey {      String KeyName() default "" ; } 定义注解的关键字是 @interface,该注解上还有 @Target (ElementType.METHOD)和 @Retention (RetentionPolicy.RUNTIME)两个注解, 这两个注解被称为"修饰注解的注解",从字面是就可以理解, @Target (ElementType.METHOD) 表示说明该注解只能注解方法, @Retention (RetentionPolicy.RUNTIME) 表示 该注解在运行时有效。 在注解体中,格式就类似于Key-Value格式,KeyName相当于就是键,值则可以在使用注解的时候获取,像Person类中的 @MapKey (KeyName = "Name" ),这里也赋予了一个默认值为空字符串 注解定义和使用后,我们对Map2Pojo工具类稍作修改,修改后完整源码如下: 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 public class Main {      private static Map<String, String> input = new HashMap<String, String>();      static {          input.put( "Name" , "Boaz" );          input.put( "Age" , "29" );      }      public static void main(String[] args) {          Person person = Map2Pojo(input, Person. class );          System.out.print(person);      }      private static <T> T Map2Pojo(Map input, Class<T> clazz) {          Method[] methods = clazz.getMethods();          T t;          try {              t = clazz.newInstance();          } catch (Exception e) {              e.printStackTrace();              return null ;          }          for (Method method : methods) {              input.keySet().forEach((key) -> {                  if (method.getAnnotations().length == 1 ) {                      MapKey mapKey = (MapKey) method.getAnnotations()[ 0 ];                      String realKey = mapKey.KeyName();                      if (key.equals(realKey)) {                          try {                              method.invoke(t, input.get(key));                          } catch (Exception e) {                              e.printStackTrace();                              return ;                          }                      }                  }                  if (( "set" + key).equals(method.getName().toLowerCase())) {                      try {                          method.invoke(t, input.get(key));                      } catch (Exception e) {                          e.printStackTrace();                          return ;                      }                  }              });          }          return t;      } } 修改的部分在22-33行,这里就读取了每个Method的注解MapKey,然后获取注解MapKey中的KeyName值来同Map中的key值进行映射。 这个示例中的注解为运行时注解,大多数自定义注解都是运行时注解。从我的角度来理解,注解可以算做是一种增加重用的机制,在这个示例中,新增了一个注解,Person类就可以在改变注解值的情况下适配不同的Map的Key值!

    转载请注明原文地址: https://ju.6miu.com/read-1297328.html
    最新回复(0)