zoukankan      html  css  js  c++  java
  • 反射与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的属性完成控制,从而使得整体代码变得简洁.

  • 相关阅读:
    Linkedin工程师是如何优化他们的Java代码的
    如何调试 Android 上 HTTP(S) 流量
    Facebook工程师是如何改进他们Android客户端的
    modified: xxx(modified content, untracked content)
    在Android工程中加入AIDL文件时,gen目录生成的文件报错-问题解决
    Ubuntu14.04LTS下使用eclipse搭建Cocos2d-x的Android环境
    Ubuntu Linux下安装Oracle JDK
    查看Android源码版本
    Ubuntu Linux下安装Oracle JDK
    Android Initializing a Build Environment
  • 原文地址:https://www.cnblogs.com/skykuqi/p/11445785.html
Copyright © 2011-2022 走看看