反射与Annotation
Posted skykuqi
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了反射与Annotation相关的知识,希望对你有一定的参考价值。
一.反射与Annotation
从JDK1.5之后,java开发提供了Annotation技术支持,这种技术为项目的编写带来的新的模型,经过了多年的发展,Annotation的技术得到了非常广泛的应用,并且已经在所有的项目开发之中都会存在.
--获取Annotation:在进行类或方法定义的时候都可以使用一系列的Annotation进行色声明,于是如果要想获取这些Annotation的信息,那么就可以直接通过反射来完成.在java.lang.reflect里面,有一个叫做AccessibleObject类,在这个类中提供有获取Annotation的方法:
获取全部Annotation: public Annotation[] getAnnotations()
获取指定的Annotation: public <T extends Annotation> T getAnnotation(Class<T> annotationClass)
--范例:定义一个接口,并且在接口上使用Annotation
1 package 反射.反射与Annotation;
2
3 import java.lang.annotation.Annotation;
4
5 /**
6 * @author : S K Y
7 * @version :0.0.1
8 */
9 @FunctionalInterface
10 @Deprecated
11 interface IMessage //存在两个Annotation注解
12 public void send();
13
14
15 @SuppressWarnings("serial")
16 class MessageImpl implements IMessage
17 @Override
18 public void send()
19 System.out.println("消息发送...");
20
21
22
23 public class AnnotationDemo
24 public static void main(String[] args)
25 //获取接口上的Annotation信息
26 Annotation[] annotations = IMessage.class.getAnnotations(); //获取接口上的所有的Annotation
27 for (Annotation annotation : annotations)
28 System.out.println(annotation);
29
30
31
--运行结果
@java.lang.FunctionalInterface()
@java.lang.Deprecated()
Process finished with exit code 0
--尝试获取实现类的注解信息
1 public class AnnotationDemo
2 public static void main(String[] args)
3 //获取接口上的Annotation信息
4 Annotation[] annotations = IMessage.class.getAnnotations(); //获取接口上的所有的Annotation
5 for (Annotation annotation : annotations)
6 System.out.println(annotation);
7
8 System.out.println("=========================");
9 //获取子类上的Annotation
10 Annotation[] implAnnotations = MessageImpl.class.getAnnotations();
11 for (Annotation implAnnotation : implAnnotations)
12 System.out.println(implAnnotation);
13
14
15
--运行结果
@java.lang.FunctionalInterface()
@java.lang.Deprecated()
=========================
Process finished with exit code 0
--发现并没有获取到注解@SuppressWarnings("serial"),其原因是该注解无法在程序执行的时候获取.那么尝试获取MessageImpl.send()方法上的Annotation会怎么样呢:
1 public class AnnotationDemo
2 public static void main(String[] args) throws NoSuchMethodException
3 //获取接口上的Annotation信息
4 Annotation[] annotations = IMessage.class.getAnnotations(); //获取接口上的所有的Annotation
5 for (Annotation annotation : annotations)
6 System.out.println(annotation);
7
8 System.out.println("=========================");
9 //获取子类上的Annotation
10 Annotation[] implAnnotations = MessageImpl.class.getAnnotations();
11 for (Annotation implAnnotation : implAnnotations)
12 System.out.println(implAnnotation);
13
14 //尝试获取MessageImpl.toString()方法上的Annotation
15 System.out.println("==============================");
16 Method send = MessageImpl.class.getDeclaredMethod("send");
17 Annotation[] sendAnnotations = send.getAnnotations();
18 for (Annotation sendAnnotation : sendAnnotations)
19 System.out.println(sendAnnotation);
20
21
22
--运行结果
@java.lang.FunctionalInterface()
@java.lang.Deprecated()
=========================
==============================
Process finished with exit code 0
--可以发现也无法在运行时获取到 @Override注解的相关信息.不同的Annotation有他的存在的范围:
@FunctionalInterface:
@Documented
@Retention(RetentionPolicy.RUNTIME) //描述的是运行是生效
@Target(ElementType.TYPE)
public @interface FunctionalInterface
@SuppressWarnings("serial"):
@Target(TYPE, FIELD, METHOD, PARAMETER, CONSTRUCTOR, LOCAL_VARIABLE)
@Retention(RetentionPolicy.SOURCE) //描述的是在源代码时生效
public @interface SuppressWarnings
String[] value();
--可以发现"@FunctionalInterface"是在程序运行时生效的Annotation,所以当程序执行的时候可以获取此Annotation,而"@SuppressWarnings"是在源代码编写的时候有效.管观察RetentionPolicy的定义:
public enum RetentionPolicy
SOURCE,
CLASS,
RUNTIME
--在RetentionPolicy枚举类中还存在一个class的定义指的是在类定义的时候生效.
二.自定义Annotation
现在已经清楚了Annotation的获取,以及Annotation的运行策略,但是最为关键性的因素是如何可以实现自定义的Annotation.为此在java中提供有新的语法使用"@interface"来定义Annotation.
范例:自定义Annotation
1 package 反射.反射与Annotation;
2
3 import java.lang.annotation.Retention;
4 import java.lang.annotation.RetentionPolicy;
5 import java.lang.reflect.InvocationTargetException;
6 import java.lang.reflect.Method;
7
8 /**
9 * @author : S K Y
10 * @version :0.0.1
11 */
12 @Retention(RetentionPolicy.RUNTIME)
13 //定义Annotation运行时的策略
14 @interface DefaultAnnotation //自定义的Annotation,
15 public String title(); //获取数据
16
17 public String url() default "获取数据的默认值"; //获取数据,默认值
18
19
20 class Message
21 @DefaultAnnotation(title = "sendMessage") //title不具备默认值,因此必须去显示的定义
22 public void send(String msg)
23 System.out.println("[消息发送]" + msg);
24
25
26
27 public class MyAnnotationDemo
28 public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException
29 Method method = Message.class.getDeclaredMethod("send", String.class); //获取指定的方法
30 DefaultAnnotation annotation = method.getAnnotation(DefaultAnnotation.class);//获取指定的Annotation1
31 String title = annotation.title(); //直接调用Annotation中的方法
32 String url = annotation.url();
33 System.out.println(title + " " + url);
34 String msg = annotation.title() + " " + url;
35 method.invoke(Message.class.getDeclaredConstructor().newInstance(),msg); //利用反射实现消息的发送
36
37
--运行结果
sendMessage 获取数据的默认值
[消息发送]sendMessage 获取数据的默认值
Process finished with exit code 0
--使用Annotation之后的最大特点是可以结合反射机制实现程序的处理.
三.工厂设计模式与Annotation整合
在清楚了Annotation的整体作用之后,但是Annotation在开发之中,到底可以完成什么样的功能.为了更好的理解Annotation的处理操作的目的,下面将结合工厂设计模式来应用Annotation操作.
1 package 反射.Annotation与工厂设计模式整合;
2
3
4 import java.lang.reflect.InvocationHandler;
5 import java.lang.reflect.Method;
6 import java.lang.reflect.Proxy;
7
8 /**
9 * @author : S K Y
10 * @version :0.0.1
11 */
12 interface IMessage
13 public void send(String msg);
14
15
16 class MessageImpl implements IMessage
17 @Override
18 public void send(String msg)
19 System.out.println("[消息发送]" + msg);
20
21
22
23 class MessageProxy implements InvocationHandler
24 private Object target;
25
26
27 public Object bind(Object target)
28 this.target = target;
29 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
30
31
32 public boolean connect()
33 System.out.println("[代理操作]进行消息发送通道的连接");
34 return true;
35
36
37 public void close()
38 System.out.println("[代理操作]关闭连接通道.");
39
40
41 @Override
42 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
43 try
44 if (this.connect())
45 return method.invoke(this.target, args);
46 else
47 throw new Exception("[error]消息无法进行发送");
48
49 finally
50 this.close();
51
52
53
54
55 class Factory
56 private Factory()
57
58 public static <T> T getInstance(Class<T> tClass) //直接返回一个实例化的操作对象
59 try
60 return (T) new MessageProxy().bind(tClass.getDeclaredConstructor().newInstance());
61 catch (Exception e)
62 e.printStackTrace();
63 return null;
64
65
66
67 class MessageService
68 private IMessage message;
69
70 public MessageService()
71 this.message = Factory.getInstance(MessageImpl.class);
72
73 public void send(String msg)
74 this.message.send(msg);
75
76
77 public class AnnotationFactoryDemo
78 public static void main(String[] args) throws IllegalAccessException, InstantiationException
79 MessageService service = new MessageService();
80 service.send("hello");
81
82
83
--运行结果
[代理操作]进行消息发送通道的连接
[消息发送]hello
[代理操作]关闭连接通道.
Process finished with exit code 0
--上述代码的实现每次都需要在MessageService类中给出MessageImpl.class的声明,使用注解形式来简化代码
1 package 反射.Annotation与工厂设计模式整合;
2
3
4 import java.lang.annotation.Retention;
5 import java.lang.annotation.RetentionPolicy;
6 import java.lang.reflect.InvocationHandler;
7 import java.lang.reflect.Method;
8 import java.lang.reflect.Proxy;
9
10 /**
11 * @author : S K Y
12 * @version :0.0.1
13 */
14 interface IMessage
15 public void send(String msg);
16
17
18 class MessageImpl implements IMessage
19 @Override
20 public void send(String msg)
21 System.out.println("[消息发送]" + msg);
22
23
24
25 class MessageProxy implements InvocationHandler
26 private Object target;
27
28
29 public Object bind(Object target)
30 this.target = target;
31 return Proxy.newProxyInstance(target.getClass().getClassLoader(), target.getClass().getInterfaces(), this);
32
33
34 public boolean connect()
35 System.out.println("[代理操作]进行消息发送通道的连接");
36 return true;
37
38
39 public void close()
40 System.out.println("[代理操作]关闭连接通道.");
41
42
43 @Override
44 public Object invoke(Object proxy, Method method, Object[] args) throws Throwable
45 try
46 if (this.connect())
47 return method.invoke(this.target, args);
48 else
49 throw new Exception("[error]消息无法进行发送");
50
51 finally
52 this.close();
53
54
55
56
57 class Factory
58 private Factory()
59
60 public static <T> T getInstance(Class<T> tClass) //直接返回一个实例化的操作对象
61 try
62 return (T) new MessageProxy().bind(tClass.getDeclaredConstructor().newInstance());
63 catch (Exception e)
64 e.printStackTrace();
65 return null;
66
67
68
69 @Retention(RetentionPolicy.RUNTIME)
70 @interface UseMessage
71 public Class<?> thisClass();
72
73 @UseMessage(thisClass = MessageImpl.class)
74 class MessageService
75 private IMessage message;
76
77 public MessageService()
78 UseMessage annotation = MessageService.class.getAnnotation(UseMessage.class);
79 this.message = (IMessage) Factory.getInstance(annotation.thisClass());
80
81 public void send(String msg)
82 this.message.send(msg);
83
84
85 public class AnnotationFactoryDemo
86 public static void main(String[] args) throws IllegalAccessException, InstantiationException
87 MessageService service = new MessageService();
88 service.send("hello");
89
90
91
--这样我们就可以依据注解来修改整个程序的功能实现.由于Annotation的存在,对于面向接口的配置处理可以直接利用Annotation的属性完成控制,从而使得整体代码变得简洁.
以上是关于反射与Annotation的主要内容,如果未能解决你的问题,请参考以下文章