JAVA自定义注解示例详解

什么是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值!

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值