什么是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"
);
}
|
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;
}
}
|
1
2
3
4
5
6
|
private
static
Map input =
new
HashMap();
static
{
input.put(
"Name"
,
"Boaz"
);
input.put(
"Age"
,
"29"
);
}
|
很多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值!