进阶Java编程(13)反射与Annotation

1,反射取得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 com.mufasa.demo1;
 2 
 3 import java.lang.annotation.Annotation;
 4 import java.lang.reflect.Method;
 5 
 6 public class JavaAPIDemo {
 7     public static void main(String[] args) throws NoSuchMethodException {
 8         {//获取接口上的Annotation信息
 9             Annotation[] annotations=IMessage.class.getAnnotations();
10             for(Annotation temp:annotations){
11                 System.out.println(temp);
12             }
13         }
14         System.out.println("-------");
15         {//①获取MessageImpl子类上的Annotation,失败;②获取MessageImpl.toString方法
16             Method method=MessageImpl.class.getDeclaredMethod("send", String.class);
17             Annotation[] annotations=method.getAnnotations();
18             for(Annotation temp:annotations){
19                 System.out.println(temp);
20             }
21         }
22     }
23 }
 1 package com.mufasa.demo1;
 2 /*
 3 什么是函数式接口(Functional Interface)
 4 其实之前在讲Lambda表达式的时候提到过,所谓的函数式接口,当然首先是一个接口,然后就是在这个接口里面只能有一个抽象方法。
 5 这种类型的接口也称为SAM接口,即Single Abstract Method interfaces。
 6 函数式接口用途
 7 它们主要用在Lambda表达式和方法引用(实际上也可认为是Lambda表达式)上。
 8  */
 9 @FunctionalInterface
10 @Deprecated(since = "1.5")
11 interface IMessage {//现在这里有两个Annotation
12     public void send(String msg);
13 }
 1 package com.mufasa.demo1;
 2 
 3 import java.io.Serializable;
 4 
 5 @SuppressWarnings("serial")//无法在程序执行的时候获取
 6 public class MessageImpl implements IMessage, Serializable {
 7     @Override
 8     public void send(String msg) {
 9         System.out.println("【消息发送】"+msg);
10     }
11 }

  不同的Annotation有它存在的范围,下面对比两个Annotation:

  现在发现【@FunctionalInterface】是在运行时生效的Annotation,所以当程序执行的时候可以获取此Annotation,而【@SuppressWarnings】是在源代码编写的时候有效。而在【RetentionPolicy】枚举类中还有一个class的定义,指的是类定义的时候生效。

2,自定义Annotation

   现在已经清楚了Annotation的获取,以及Annotation的运行策略,但是最为关键性的一个因素是如何可以实现自定义的Annotation呢?为此在Java里面提供有新的语法,使用【@interface】来定义Annotation。

  ·范例:自定义Annotation

 1 package com.mufasa.demo2;
 2 
 3 import java.lang.annotation.Retention;
 4 import java.lang.annotation.RetentionPolicy;
 5 
 6 @Retention(RetentionPolicy.RUNTIME)//定义Annotation的运行策略
 7 @interface DefaultAnnotation {//自定义Annotation
 8     public String title();//获取数据
 9     public String url() default "www.cnblogs.com";//获取数据,默认值
10 }
 1 package com.mufasa.demo2;
 2 
 3 import java.lang.reflect.InvocationTargetException;
 4 import java.lang.reflect.Method;
 5 
 6 public class JavaAPIDemo {
 7     public static void main(String[] args) throws NoSuchMethodException, IllegalAccessException, InvocationTargetException, InstantiationException {
 8         Method method=Message.class.getMethod("send", String.class);//获取指定方法
 9         DefaultAnnotation annotation=method.getAnnotation(DefaultAnnotation.class);//获取指定Annotation
10 //        System.out.println(annotation.title());
11 //        System.out.println(annotation.url());
12         String msg=annotation.title()+"("+annotation.url()+")";//消息内容
13         method.invoke(Message.class.getDeclaredConstructor().newInstance(),msg);
14     }
15 }

  使用Annotation之后最大的特点就是可以结合反射机制实现程序的处理。

3,工厂设计模式与Annotation整合

   现在已经清楚Annotation的整体作用,但是Annotation在开发之中能做哪些事情呢?为了帮助大家进一步理解Annotation的处理目的下面将结合工厂设计模式来应用Annotation操作。

1 package com.mufasa.demo3;
2 
3 import java.lang.annotation.Retention;
4 import java.lang.annotation.RetentionPolicy;
5 
6 @Retention(RetentionPolicy.RUNTIME)
7 public @interface UseMessage {
8     public Class<?> clazz();
9 }
 1 package com.mufasa.demo3;
 2 
 3 @UseMessage(clazz = MessageImpl.class)//!!!通过注解来控制整个程序的完成!!!
 4 public class MessageService {
 5     private IMessage message;
 6     public MessageService(){
 7         UseMessage useMessage=MessageService.class.getAnnotation(UseMessage.class);
 8         this.message=(IMessage) Factory.getInstance(useMessage.clazz());
 9     }
10     public void send(String msg){
11         this.message.send(msg);
12     }
13 }
 1 package com.mufasa.demo3;
 2 
 3 public class JavaAPIDemo {
 4     public static void main(String[] args){
 5         //①普通
 6 //        IMessage msg=Factory.getInstance(MessageImpl.class);
 7 //        msg.send("www.cnblogs.com");
 8         //②特殊
 9         MessageService messageService=new MessageService();
10         messageService.send("www.cnblogs.com");
11     }
12 }
13 /*
14 【代理连接】进行消息发送通道的连接
15 【消息发送】www.cnblogs.com
16 【代理断开】关闭连接通道
17  */
 1 package com.mufasa.demo3;
 2 
 3 import java.lang.reflect.InvocationTargetException;
 4 
 5 class Factory {
 6     private Factory(){}
 7     public static <T> T getInstance(Class<T> clazz){//直接返回实例化操作对象
 8         try{
 9             return (T) new MessageProxy().bind(clazz.getDeclaredConstructor().newInstance());
10         }catch (Exception e){
11             e.printStackTrace();
12             return null;
13         }
14     }
15 }

  由于Annotation的存在,所以对于面向接口的编程的配置处理将可以直接利用Annotation的属性完成控制,从而使得整体代码变得简洁。

原文地址:https://www.cnblogs.com/Mufasa/p/11186113.html