通过自定义JAVA注解来理解JAVA注解

    xiaoxiao2025-05-26  10

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

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

    作用分类: ①编写文档:通过代码里标识的元数据生成文档【生成文档doc文档】 ②代码分析:通过代码里标识的元数据对代码进行分析【使用反射】 ③编译检查:通过代码里标识的元数据让编译器能够实现基本的编译检查【Override】

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

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

    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:

    private static Map input = new HashMap(); static{ input.put("name", "Boaz"); input.put("age", "29"); }

    需求是把这个HashMap的值转换为Person这个pojo类,map中的key值和Person类中的属性名是相同的,我们使用反射的方式来实现,完整代码如下:

    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:

    private static Map input = new HashMap(); static { input.put("Name", "Boaz"); input.put("Age", "29"); }

    跟之前的Map没有什么不同,只是key值的首字母大写了,显然,上面的Map2Pojo工具类这个时候就不能工作了。Map2Pojo是一个通用类,可以为很多Pojo转换服务,在这个类里为这个情况添加if-else来单位为Person这个变化来处理是不合适的。

    这个时候就是注解登场了,我们在Person类中增加如下自定义注解:

    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,这是一个自定义注解,该注解源码如下:

    @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工具类稍作修改,修改后完整源码如下:

    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; } }

    修改的部分在21-33行,这里就读取了每个Method的注解MapKey,然后获取注解MapKey中的KeyName值来同Map中的key值进行映射。

    这个示例中的注解为运行时注解,大多数自定义注解都是运行时注解。从我的角度来理解,注解可以算做是一种增加重用的机制,在这个示例中,新增了一个注解,Person类就可以在改变注解值的情况下适配不同的Map的Key值!

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