# 注解
# 概念
JDK 1.5引入了一个很重要特性就是对元数据(Metadata)的支持,在J2SE 5.0中,这种元数据被称为注解(Annotation),注解可以在不改变原有逻辑的情况下加一些补充信息来说明程序,与类、接口、枚举是在同一个层次。它可以声明在包、类、字段、方法、局部变量、方法参数等的前面,用来对这些元素进行说明,注释。
注解作为简化程序配置的一种手段,在Java中一般都是方法前@开头的标注。注解一般应用在哪些方面呢?
- 在程序中写配置信息,这个时候有什么改动都需要修改源文件,非常不便,比如服务器地址改变了,要在源码中修改服务器的地址。注意在配置文件中写配置信息,在配置项不多的情况下挺好用,但是配置项比较多的时候就难以维护了。将配置信息重新写回程序中,利用注解来将配置信息与程序分离,现在基本是注解+配置文件。
- 编写文档,生成doc文档,代码分析,编译检查。
# 注解基础
Java中可以自定义Annotation,定义时可使用@interface进行标记,同时可使用@Target定义Annotation范围。定义格式为:
元注解
public @interface 注解名称{
属性列表;
}
1
2
3
4
2
3
4
注解本质上就是一个接口,该接口默认继承Annotation接口。利用反射获取注解,其实就是在内存中生成了一个该注解接口的子类实现对象。
# 属性
对于上面属性的返回值要求有几种:
- 基本数据类型
- String
- 枚举
- 注解
- 以上类型的数组
对属性赋值时注意:
- 如果定义属性时,使用default关键字给属性默认初始化值,则使用注解时,可以不进行属性的赋值。
- 如果只有一个属性需要赋值,并且属性的名称是value,则value可以省略,直接定义值即可。
- 数组赋值时,值使用{}包裹。如果数组中只有一个值,则{}可以省略。
# 元注解
元注解是用于描述注解的注解。
- @Target:描述注解能够作用的位置
- @Retention:描述注解被保留的阶段
- @Documented:描述注解是否被抽取到api文档中
- @Inherited:描述注解是否被子类继承
# Target
它用于描述注解能够作用的位置,会使用ElementType枚举变量,它的取值如下:
# Retention
它用于描述注解被保留的阶段,使用RetentionPolicy枚举变量,它的取值如下:
- SOURCE:这种Annotation类型信息只保留在源文件(.java)中,编译后不会保存在编译好的类文件(.class)中。
- CLASS:此Annotation类型将保留在源文件(.java)和编译后的类文件中(.class)中,使用此类时,Annotation信息不会被加载到虚拟机JVM中。一个注解如果没有指定范围,默认是此范围。
- RUNTIME:此类Annotation信息会被保留在源文件(.java),类文件(.class)和JVM中。
# 基本使用
下面是它的基本使用方法:
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
import java.lang.annotation.RetentionPolicy;
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface myAnnotation{
public String name();
public String info() default "defaultInfo";
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface myOwnAnnotation{
public String value();
//public String name();
public String info() default "defaultInfo";
}
class MyClass{
@myAnnotation(name="xie")
public void Info(String info) {
System.out.println("信息:"+info);
}
//如果注解只有一个需要用户设置的必要属性时,可以使用Value作为属性名称,
@myOwnAnnotation("li")
public void Info2(String info2) {
System.out.println("信息2:"+info2);
}
}
public class Main {
public static void main(String[] args) throws Exception {
Method method = MyClass.class.getMethod("Info", String.class);
myAnnotation myAnno = method.getAnnotation(myAnnotation.class);
method.invoke(MyClass.class.getDeclaredConstructor().newInstance(), myAnno.name()+":"+myAnno.info());
Method method2 = MyClass.class.getMethod("Info2", String.class);
myOwnAnnotation myAnno2 = method2.getAnnotation(myOwnAnnotation.class);
method2.invoke(MyClass.class.getDeclaredConstructor().newInstance(), myAnno2.value()+":"+myAnno2.info());
}
}
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
47
48
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
47
48
# 常用注解
下面是三个常用注解:
- @Override,标记该方法是要重写父类的方法。
- @Deprecated,标记该方法在后面要被遗弃。
- @SuppressWarnings,压制某类警告信息。 @SuppressWarnings(value={"警告类别"}),它拥有的警告类别有:deprecation,unchecked,fallthrough,path,serial,finally,all。
# 应用案例
# 反射获取注解信息
import java.io.Serializable;
import java.lang.annotation.Annotation;
@FunctionalInterface
@Deprecated(since = "9.0")
interface IMyOper{
public void OpenInfo(String info);
}
@Deprecated(since = "2.0")
@SuppressWarnings("serial")
class Computer implements IMyOper,Serializable{
@Deprecated(since = "1.0")
@Override
public void OpenInfo(String info) {
// TODO Auto-generated method stub
System.out.println("hello");
}
}
public class Main {
public static void main(String[] args) throws Exception {
PrintAnnotations(IMyOper.class.getAnnotations());
PrintAnnotations(Computer.class.getAnnotations());
PrintAnnotations(Computer.class.getDeclaredMethod("OpenInfo", String.class).getAnnotations());
}
public static void PrintAnnotations(Annotation annotations[]) {
System.out.println("--------------------");
for(Annotation temp:annotations) {
System.out.println(temp);
}
}
}
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
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
# 通过反射注解生成新类
下面是通过注解和反射来创建任意类对象,并执行其中某些方法。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
class TestClass {
public void Show() {
System.out.println("This is my TestClass show method");
}
}
@Target({ElementType.TYPE})
@Retention(RetentionPolicy.RUNTIME)
@interface MyClassInfo {
String className();
String methodName();
}
@MyClassInfo(className = "TestClass",methodName = "Show")
public class Main {
public static void main(String[] args) throws Exception {
Class<Main> reflectTestClass = Main.class;
MyClassInfo myAnnotation = reflectTestClass.getAnnotation(MyClassInfo.class);
String className = myAnnotation.className();
String methodName = myAnnotation.methodName();
System.out.println("className:"+className+",methodName:"+methodName);
Class cls = Class.forName(className);
Object obj = cls.newInstance();
Method method = cls.getMethod(methodName);
method.invoke(obj);
}
}
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
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
# 简单测试框架
下面通过注解反射来实现一个简单测试框架,下面会对TestClass中有checkError注解的方法进行测试,如果有问题,就写入到error.txt中:
import java.io.BufferedWriter;
import java.io.FileWriter;
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;
import java.lang.reflect.Method;
@Target({ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface checkError {
}
class TestClass {
@checkError
public void Calculate1() {
int temp = 10/0;
}
public void Calculate2() {
int temp = 10/0;
}
@checkError
public void Calculate3() {
int temp = 100/0;
}
public void Show() {
System.out.println("This is my TestClass show method");
}
}
public class Main {
public static void main(String[] args) throws Exception {
TestClass targetTestClass = new TestClass();
Class cls = targetTestClass.getClass();
Method[] methods = cls.getMethods();
int number = 0;//出现异常的次数
BufferedWriter bw = new BufferedWriter(new FileWriter("error.txt"));
for (Method method : methods) {
if(method.isAnnotationPresent(checkError.class)){
try {
System.out.println(method.getName());
method.invoke(targetTestClass);
} catch (Exception e) {
//记录到文件中
number ++;
bw.write(method.getName()+ " 方法出异常了");
bw.newLine();
bw.write("异常的名称:" + e.getCause().getClass().getSimpleName());
bw.newLine();
bw.write("异常的原因:"+e.getCause().getMessage());
bw.newLine();
bw.write("--------------------------");
bw.newLine();
}
}
}
bw.write("本次测试一共出现 "+number+" 次异常");
bw.flush();
bw.close();
}
}
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
# Annotation整合工厂模式
使用Annotation开发可以将配置信息写入Annotation后,在项目启动时通过反射获取相应Annotation定义并进行操作,下面使用Annotation整合工厂设计模式与代理设计模式。
import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.Target;
import java.lang.reflect.InvocationHandler;
import java.lang.reflect.Method;
import java.lang.reflect.Proxy;
import java.lang.annotation.RetentionPolicy;
interface IDealInfo{
public void dealInfo(String info);
}
class Computer implements IDealInfo{
@Override
public void dealInfo(String info) {
// TODO Auto-generated method stub
System.out.println("computer:"+info);
}
}
class Phone implements IDealInfo{
@Override
public void dealInfo(String info) {
// TODO Auto-generated method stub
System.out.println("phone:"+info);
}
}
class DeviceFactory{
private DeviceFactory() {};
public static <T> T GetInstance(Class<T> myClass) {
try {
return (T) new UseDeviceProxy().bind(myClass.getDeclaredConstructor().newInstance());
} catch (Exception e) {
// TODO: handle exception
return null;
}
}
}
@Target({ElementType.TYPE,ElementType.METHOD})
@Retention(RetentionPolicy.RUNTIME)
@interface UseDevice{
public Class<?> myClass();
}
@UseDevice(myClass = Phone.class)
class DealInfoService{
private IDealInfo iDealInfo;
public DealInfoService() {
UseDevice useDevice = DealInfoService.class.getAnnotation(UseDevice.class);
this.iDealInfo = (IDealInfo)DeviceFactory.GetInstance(useDevice.myClass());
}
public void DealInfo(String msg) {
this.iDealInfo.dealInfo(msg);
}
}
class UseDeviceProxy implements InvocationHandler{
private Object target;
public Object bind(Object target) {
this.target = target;
return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
}
public void Oper1() {
System.out.println("oper1!");
}
public void Oper2() {
System.out.println("oper2!");
}
@Override
public Object invoke(Object proxy, Method method, Object[] args) throws Throwable {
// TODO Auto-generated method stub
Oper1();
Oper2();
return method.invoke(this.target,args);
}
}
public class Main {
public static void main(String[] args) throws Exception {
DealInfoService dealInfoService = new DealInfoService();
dealInfoService.DealInfo("hello world!");
}
}
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
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
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97